获取对象实例上的自定义属性的* value *?

时间:2011-10-25 13:07:52

标签: c# reflection customtypedescriptor runtime-type

使用.NET 4,C#

假设我的课程Info延伸CustomTypeDescriptor。类Info的实例具有<string, object>对的字典,在运行时加载。

我希望能够将字典键公开为属性(以便Info的每个实例都具有不同的属性)。属性的值应该是字典中的相应值。

我开始露出属性:

    public override PropertyDescriptorCollection GetProperties()
    {

        var orig = base.GetProperties();
        var newProps = dictionary.Select( kvp => 
                       TypeDescriptor.CreateProperty(
                           this.GetType(), 
                           kvp.key, 
                           typeof(string)));
        return new PropertyDescriptorCollection(
                   orig.Cast<PropertyDescriptor>()
                   .Concat(newProps)
                   .ToArray());
    }

问题是,我如何获得他们的价值观?

var info = new Info(new Dictionary<string, object>{{"some_property", 5}};
var prop = TypeDescriptor.GetProperties(i_info)["some_property"];
var val = prop.GetValue(i_info); //should return 5

我在调用prop.GetValue()时找到控件的唯一方法是覆盖GetPropertyOwner(PropertyDescriptor pd),但我理解它的方式,它希望我返回另一个类型的实例具有匹配的真实(已编译)属性。

我希望能够自己编写属性的实际实现(对于此示例,返回其键与属性名称匹配的字典中的值)。

这可能吗?

2 个答案:

答案 0 :(得分:3)

您需要自己实现PropertyDescriptor类重写GetValue方法。因此,您将使用新的TypeDescriptor.CreateProperty或类似内容而不是MyCoolPropertyDescriptor(dictionary, kvp.Key)

以下是如何实施的示例:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace ConsoleApplication1
{
    internal sealed class MyCoolPropertyDescriptor : PropertyDescriptor
    {
        private Func<object, object> propertyGetter;
        private Action<object, object> propertySetter;

        public MyCoolPropertyDescriptor(
            string name,
            Func<object, object> propertyGetter,
            Action<object, object> propertySetter)
            : base(name, new Attribute[] {})
        {
            this.propertyGetter = propertyGetter;
            this.propertySetter = propertySetter;
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override System.Type ComponentType
        {
            get { return typeof(object); }
        }

        public override object GetValue(object component)
        {
            return this.propertyGetter(component);
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override System.Type PropertyType
        {
            get { return typeof(object); }
        }

        public override void ResetValue(object component)
        {
            this.propertySetter(component, null);
        }

        public override void SetValue(object component, object value)
        {
            this.propertySetter(component, value);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }

    public sealed class Info : CustomTypeDescriptor
    {
        IDictionary<string, object> properties;

        public Info(IDictionary<string, object> properties)
        {
            this.properties = properties;
        }

        public override PropertyDescriptorCollection GetProperties()
        {
            var orig = base.GetProperties();
            var newProps = this.properties
                .Select(kvp => new MyCoolPropertyDescriptor(
                    kvp.Key,
                    o => ((Info)o).properties[kvp.Key],
                    (o, v) => ((Info)o).properties[kvp.Key] = v));

            return new PropertyDescriptorCollection(orig
                .Cast<PropertyDescriptor>()
                .Concat(newProps)
                .ToArray());
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var info = new Info(new Dictionary<string, object>{{"some_property", 5}});
            var prop = TypeDescriptor.GetProperties(info)["some_property"];
            var val = prop.GetValue(info); //should return 5
            Console.WriteLine(val);
        }
    }
}

答案 1 :(得分:2)

我对CustomTypeDescriptor的理解是它允许数据绑定将额外的属性暴露给网格,这些属性实际上并不存在于类中。它不是扩展CLR的东西,所以你的实际类暴露了属性。

如果您想要实际的CLR属性,那么您需要查看DynamicObjectExpandoObject以获得我认为您正在使用的功能。