#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 integerCount
, это было быtypeof(int)
.componentType
— это тип класса, который обладает динамическими свойствами, напримерtypeof(MyDynamicPropertyClass)
.3. Еще один вопрос. Таким образом, если к свойству, ранее добавленному через
Properties
список, осуществляется динамический доступ (например, с помощьюvar
), могу ли я быть уверен, что оноGetProperties()
используется для доступа к указанному свойству?4. К сожалению, нет. Реализация динамических свойств, подобных этому, работает только тогда, когда клиент (объект, фактически просматривающий, считывающий и записывающий свойства) поддерживает
TypeDescriptor
способ выполнения действий. Это иногда называют «компонентной моделью», и не все потребители свойств поддерживают ее. Например, WPF действительно поддерживает это, например, для привязки данных. Кроме того, WinForms поддерживает компонентную модель дляPropertyGrid
. Но в других местах свойства — это просто свойства, и компонентная модель не используется. Самое простое — посмотреть, работает ли это для вашего приложения.