149

是否可以在运行时添加属性或在运行时更改属性的值?

4

10 回答 10

71

这实际上取决于您要完成的工作。

System.ComponentModel.TypeDescriptor东西可用于向类型、属性和对象实例添加属性,但它的限制是您也必须使用它来检索这些属性。如果您正在编写使用这些属性的代码,并且您可以生活在这些限制内,那么我肯定会建议您这样做。

据我所知,PropertyGrid 控件和 Visual Studio 设计图面是 BCL 中唯一消耗 TypeDescriptor 内容的东西。事实上,这就是他们真正需要做的大约一半事情的方式。

于 2008-09-24T19:35:44.017 回答
67

属性是静态元数据。程序集、模块、类型、成员、参数和返回值不是 C# 中的第一类对象(例如,System.Type类只是类型的反映表示)。您可以获取类型的属性实例并更改属性(如果它们是可写的),但这不会影响属性,因为它应用于类型。

于 2008-09-24T19:31:42.857 回答
11

你不能。一种解决方法可能是在运行时生成派生类并添加属性,尽管这可能有点矫枉过正。

于 2008-09-24T19:31:10.737 回答
11

好吧,只是为了与众不同,我发现一篇文章引用了使用 Reflection.Emit 来做到这一点。

这是链接: http: //www.codeproject.com/KB/cs/dotnetattributes.aspx,您还需要查看文章底部的一些评论,因为讨论了可能的方法。

于 2008-09-24T19:37:38.287 回答
4

不,这不对。

属性是元数据,并以二进制形式存储在已编译的程序集中(这也是您只能在其中使用简单类型的原因)。

于 2008-09-24T19:28:22.990 回答
3

我不相信。即使我错了,您最好的希望是将它们添加到整个类型中,而不是类型的实例

于 2008-09-24T19:27:18.517 回答
3

如果您需要能够动态添加的东西,c# 属性不是办法。研究将数据存储在 xml 中。我最近做了一个项目,我开始使用属性,但最终转向使用 xml 的序列化。

于 2008-09-24T19:31:50.080 回答
3

为什么需要?属性为反射提供了额外的信息,但如果您从外部知道您想要哪些属性,则不需要它们。

您可以在数据库或资源文件中相对轻松地在外部存储元数据。

于 2008-09-24T19:32:12.903 回答
1

就像 Deczaloth 在下面的评论中提到的那样,我认为元数据在编译时是固定的。我通过创建一个动态对象来实现它,在该对象中我覆盖 GetType() 或使用 GetCustomType() 并编写我自己的类型。使用它,您可以...

我非常努力地使用 System.ComponentModel.TypeDescriptor 没有成功。这并不意味着它不能工作,但我想看看代码。

在对应部分,我想更改一些属性值。为此,我做了 2 个可以正常工作的功能。

        // ************************************************************************
        public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName,  string description)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, description);
                }
            }
        }

        // ************************************************************************
        public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, isReadOnly);
                }
            }
        }
于 2017-09-08T13:35:49.457 回答
-9

在 Java 中,我曾经通过使用映射和实现我自己的键值编码来解决这个问题。

http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html

于 2008-09-24T19:45:34.760 回答