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

发布于 2024-12-11 16:33:50 字数 1287 浏览 0 评论 0原文

使用 .NET 4、C#

假设​​我有一个扩展 CustomTypeDescriptorInfo 类。 Info 类的实例有一个 对的字典,在运行时加载。

我希望能够将字典键公开为属性(以便 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),但根据我的理解,它希望我返回具有匹配的真实(编译)属性的另一个类型的实例。

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

这可能吗?

Using .NET 4, C#

Let's say I have class Info that extends CustomTypeDescriptor. An instance of class Info has a dictionary of <string, object> pairs, loaded at runtime.

I'd like to be able to expose the dictionary keys as properties (so that each instance of Info has different properties). 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.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

静谧 2024-12-18 16:33:50

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

以下是如何实施的示例:


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

You need to make your own implementation of the PropertyDescriptor class overriding GetValue method. So instead of TypeDescriptor.CreateProperty you'll use new MyCoolPropertyDescriptor(dictionary, kvp.Key) or like.

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

森林散布 2024-12-18 16:33:50

我对 CustomTypeDescriptor 的理解是,它允许数据绑定向(例如,网格)公开类中实际不存在的额外属性。它不是扩展 CLR 以便您的实际类公开该属性的东西。

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

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. It's not something that extends the CLR so that your actual class exposes the property.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文