3

使用 .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()被调用时获得控制的唯一方法是 override GetPropertyOwner(PropertyDescriptor pd),但我理解它的方式是,它希望我返回具有匹配的真实(编译)属性的另一种类型的实例。

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

这可能吗?

4

2 回答 2

3

您需要自己实现PropertyDescriptor类覆盖GetValue方法。TypeDescriptor.CreateProperty因此,您将使用 newMyCoolPropertyDescriptor(dictionary, kvp.Key)或 like代替。

以下是如何实现它的示例:


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

于 2011-10-25T13:40:49.230 回答
2

我的理解CustomTypeDescriptor是,它允许数据绑定将额外的属性公开给例如网格,而这些属性实际上并不存在于类中。它不是扩展 CLR 以便您的实际类公开该属性的东西。

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

于 2011-10-25T13:45:19.633 回答