Adicione propriedades em tempo de execução

Eu tenho uma class que o programador pode usar para adicionar dinamicamente novas propriedades. Para isso, ele implementa o ICustomTypeDescriptor para poder replace o método GetProperties() .

 public class DynamicProperty { public object Value { get; set; } public Type Type { get; set; } public string Name { get; set; } public Collection Attributes { get; set; } } public class DynamicClass : ICustomTypeDescriptor { // Collection to code add dynamic properties public KeyedCollection 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().ToArray()); // Fill property collection with dynamic properties (Properties) foreach (var prop in Properties) { // HOW TO? } return propsCollection; } } 

É possível iterar sobre a lista de propriedades para adicionar cada propriedade a PropertyDescriptorCollection ?

Basicamente eu quero que o programador seja capaz de adicionar um DynamicProperty a uma coleção que será manipulada por GetProperties . Algo como:

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

Agora essas Properties seriam definidas para propriedades de instância sempre que GetProperties fosse chamado. Eu estou pensando isso do jeito certo?

    Você já está criando uma coleção como esta:

     PropertyDescriptorCollection propsCollection = new PropertyDescriptorCollection(instanceProps.Cast().ToArray()); 

    Mas a coleção que você está criando só tem as propriedades existentes, não suas novas propriedades.

    Você precisa fornecer um único array concatenado das propriedades existentes e suas novas propriedades.

    Algo assim:

     instanceProps.Cast().Concat(customProperties).ToArray() 

    Próximo problema: você precisa customProperties que é uma coleção de PropertyDescriptor . Infelizmente, PropertyDescriptor é uma class abstrata, então você não tem uma maneira fácil de criar uma.

    Podemos resolver isso, apenas defina sua própria class CustomPropertyDescriptor derivando de PropertyDescriptor e implementando todos os methods abstratos.

    Algo assim:

     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; } } 

    Eu não preenchi as chamadas para obter e definir suas propriedades; essas chamadas dependem de como você implementou as propriedades dinâmicas sob o capô.

    Em seguida, você precisa criar uma matriz de CustomPropertyDescriptor preenchida com informações apropriadas para suas propriedades dinâmicas e concatená-la com as propriedades básicas, conforme descrevi inicialmente.

    O PropertyDescriptor não apenas descreve suas propriedades, mas também permite que o cliente realmente obtenha e defina os valores dessas propriedades. E esse é o ponto todo, não é!