Добавление свойств во время выполнения

#c# #properties #runtime

#c# #свойства #время выполнения

Вопрос:

У меня есть класс, который программист может использовать для динамического добавления новых свойств. Для этого он реализует метод, ICustomTypeDescriptor позволяющий переопределять GetProperties() .

 public class DynamicProperty
{
    public object Value { get; set; }

    public Type Type { get; set; }

    public string Name { get; set; }

    public Collection<Attribute> Attributes { get; set; }
}

public class DynamicClass : ICustomTypeDescriptor
{
    // Collection to code add dynamic properties
    public KeyedCollection<string, DynamicProperty> Properties
    {
        get;
        private set;
    }

    // ICustomTypeDescriptor implementation
    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        // Properties founded within instance
        PropertyInfo[] instanceProps = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

        // Fill property collection with founded properties
        PropertyDescriptorCollection propsCollection = 
            new PropertyDescriptorCollection(instanceProps.Cast<PropertyDescriptor>().ToArray());

        // Fill property collection with dynamic properties (Properties)
        foreach (var prop in Properties)
        {
            // HOW TO?
        }

        return propsCollection;
    }
}
  

Возможно ли выполнить итерацию по списку свойств, чтобы добавить каждое свойство в PropertyDescriptorCollection ?

В принципе, я хочу, чтобы программист мог добавлять DynamicProperty в коллекцию, которая будет обрабатываться GetProperties . Что-то вроде:

 new DynamicClass()
{
    Properties = {
        new DynamicProperty() {
            Name = "StringProp",
            Type = System.String,
            Value = "My string here"
        },

        new DynamicProperty() {
            Name = "IntProp",
            Type = System.Int32,
            Value = 10
        }
    }
}
  

Теперь они Properties будут устанавливаться в свойства экземпляра при каждом GetProperties вызове. Правильно ли я об этом думаю?

Ответ №1:

Вы уже создаете коллекцию, подобную этой:

 PropertyDescriptorCollection propsCollection = 
            new PropertyDescriptorCollection(instanceProps.Cast<PropertyDescriptor>().ToArray());
  

Но создаваемая вами коллекция содержит только существующие свойства, а не ваши новые свойства.

Вам необходимо предоставить единый массив, объединенный из существующих свойств и ваших новых свойств.

Что-то вроде этого:

 instanceProps.Cast<PropertyDescriptor>().Concat(customProperties).ToArray()
  

Следующая проблема: вам нужен, customProperties который является коллекцией PropertyDescriptor . К сожалению, PropertyDescriptor это абстрактный класс, поэтому у вас нет простого способа его создать.

Однако мы можем это исправить, просто определите свой собственный CustomPropertyDescriptor класс, производя от PropertyDescriptor и реализуя все абстрактные методы.

Что-то вроде этого:

 public class CustomPropertyDescriptor : PropertyDescriptor
{
    private Type propertyType;
    private Type componentType;

    public CustomPropertyDescriptor(string propertyName, Type propertyType, Type componentType)
        : base(propertyName, new Attribute[] { })
    {
        this.propertyType = propertyType;
        this.componentType = componentType;
    }

    public override bool CanResetValue(object component) { return true; }
    public override Type ComponentType { get { return componentType; } }
    public override object GetValue(object component) { return 0; /* your code here to get a value */; }
    public override bool IsReadOnly { get { return false; } }
    public override Type PropertyType { get { return propertyType; } }
    public override void ResetValue(object component) { SetValue(component, null); }
    public override void SetValue(object component, object value) { /* your code here to set a value */; }
    public override bool ShouldSerializeValue(object component) { return true; }
}
  

Я не заполнял вызовы для получения и установки ваших свойств; эти вызовы зависят от того, как вы реализовали динамические свойства под капотом.

Затем вам нужно создать массив CustomPropertyDescriptor , заполненный информацией, соответствующей вашим динамическим свойствам, и объединить его с базовыми свойствами, как я описал изначально.

PropertyDescriptor Не только описывает ваши свойства, это также позволяет клиенту фактически получать и устанавливать значения этих свойств. И в этом весь смысл, не так ли!

Комментарии:

1. propertyType правильный ли тип самого свойства? Как насчет componentType? Это тип объекта, в котором находится свойство?

2. propertyType — это тип динамического свойства. Если у вас есть вызываемое свойство dynamic integer Count , это было бы typeof(int) . componentType — это тип класса, который обладает динамическими свойствами, например typeof(MyDynamicPropertyClass) .

3. Еще один вопрос. Таким образом, если к свойству, ранее добавленному через Properties список, осуществляется динамический доступ (например, с помощью var ), могу ли я быть уверен, что оно GetProperties() используется для доступа к указанному свойству?

4. К сожалению, нет. Реализация динамических свойств, подобных этому, работает только тогда, когда клиент (объект, фактически просматривающий, считывающий и записывающий свойства) поддерживает TypeDescriptor способ выполнения действий. Это иногда называют «компонентной моделью», и не все потребители свойств поддерживают ее. Например, WPF действительно поддерживает это, например, для привязки данных. Кроме того, WinForms поддерживает компонентную модель для PropertyGrid . Но в других местах свойства — это просто свойства, и компонентная модель не используется. Самое простое — посмотреть, работает ли это для вашего приложения.