在运行时添加属性

16
我有一个类,程序员可以使用它来动态添加新属性。为此,它实现了 ICustomTypeDescriptor 接口并重写了 GetProperties() 方法。

我有一个类,程序员可以使用它来动态添加新属性。为此,它实现了 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
        }
    }
}

现在,每当调用GetProperties时,这些属性将被设置为实例属性。我这样想是否正确?

1个回答

19

你已经在创建这样的一个集合:

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

但是你创建的集合只有现有属性,没有你添加的新属性。

你需要提供一个连接了现有属性和新属性的单个数组。

像这样:

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

下一个问题是你需要一个名为customProperties的集合,其中包含PropertyDescriptor。不幸的是PropertyDescriptor是一个抽象类,因此您没有一种简单的方法来创建它。

但我们可以解决这个问题,只需通过从PropertyDescriptor派生出自己的CustomPropertyDescriptor类并实现所有抽象方法即可。

例如:

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不仅描述了您的属性,还使客户端能够实际获取和设置这些属性的值。这就是整个重点所在,不是吗!


propertyType 是属性本身的类型,对吗?那 componentType 又是什么呢?它是指属性所在对象的类型吗? - Joao
propertyType 是动态属性的类型。如果您有一个名为 Count 的动态整数属性,则其类型应为 typeof(int)componentType 是具有动态属性的类的类型,例如 typeof(MyDynamicPropertyClass) - Rick Sladkey
就一个问题。如果通过“属性”列表先前添加了属性,并且动态访问该属性(例如使用var),我可以确保使用GetProperties()来访问所述属性吗? - Joao
1
很遗憾,不行。只有在客户端(实际查找、读取和写入属性的实体)支持“TypeDescriptor”方式时,才能实现此类动态属性。这有时被称为“组件模型”,并非所有属性消费者都支持它。例如,WPF确实支持它,例如用于数据绑定。此外,WinForms支持“PropertyGrid”的组件模型。但在其他地方,属性只是属性,不使用组件模型。最简单的方法是看看它是否适用于您的应用程序。 - Rick Sladkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接