简体   繁体   English

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

[英]Get *value* of custom property on object instance?

Using .NET 4, C# 使用.NET 4,C#

Let's say I have class Info that extends CustomTypeDescriptor . 假设我有类Info来扩展CustomTypeDescriptor An instance of class Info has a dictionary of <string, object> pairs, loaded at runtime. Info的实例具有在运行时加载的<string, object>对的字典。

I'd like to be able to expose the dictionary keys as properties (so that each instance of Info has different properties). 我希望能够将字典键公开为属性(以便Info每个实例都具有不同的属性)。 The values of the properties should be the corresponding values in the dictionary. 属性的值应该是字典中的对应值。

I got around to exposing properties: 我开始暴露属性:

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

The problem is, how do I get their values? 问题是,我如何获得他们的价值观?

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

The only way I found to get control when prop.GetValue() is called was to override GetPropertyOwner(PropertyDescriptor pd) , but the way I understand it, it expects me to return the instance of another type that has a matching real (compiled) property. 调用prop.GetValue()时我发现获得控制权的唯一方法是覆盖GetPropertyOwner(PropertyDescriptor pd) ,但是我理解它的方式,它希望我返回另一个具有匹配实数(已编译)的类型的实例属性。

I'd like to be able to write the actual implementation of the property myself (for this example, return the value in the dictionary whose key matches the property name). 我希望能够自己编写属性的实际实现(对于此示例,返回其键与属性名称匹配的字典中的值)。

Is this possible? 这可能吗?

You need to make your own implementation of the PropertyDescriptor class overriding GetValue method. 您需要自己实现PropertyDescriptor类重写GetValue方法。 So instead of TypeDescriptor.CreateProperty you'll use new MyCoolPropertyDescriptor(dictionary, kvp.Key) or like. 因此,您将使用新的MyCoolPropertyDescriptor(dictionary, kvp.Key)等来代替TypeDescriptor.CreateProperty

Here is a sample of how it can be implemented: 以下是如何实施的示例:


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

My understanding of CustomTypeDescriptor is that it allows databinding to expose extra properties to, say, a grid, that don't actually exist on the class. 我对CustomTypeDescriptor理解是它允许数据绑定向网格公开额外的属性,这些属性实际上并不存在于类中。 It's not something that extends the CLR so that your actual class exposes the property. 它不是扩展CLR的东西,因此您的实际类会暴露属性。

If you want actual CLR properties then you need to look at DynamicObject or ExpandoObject to get the kind of functionality that I think you're after. 如果你想要实际的CLR属性,那么你需要查看DynamicObjectExpandoObject来获得我认为你想要的那种功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM