可以在C#中动态添加属性吗?


Answers:


67

属性是静态元数据。程序集,模块,类型,成员,参数和返回值在C#中不是一流的对象(例如,System.Type该类仅仅是类型的一种反映形式)。您可以获取类型的属性的实例,并在属性可写的情况下更改属性,但不会影响属性,因为将其应用于类型。


68

这实际上取决于您要实现的目标。

System.ComponentModel.TypeDescriptor东西可以用来添加属性类型,属性和对象实例,它有,你必须用它来读取这些属性以及限制。如果您正在编写使用这些属性的代码,并且可以在这些限制内生存,那么我绝对会建议这样做。

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


7
实际上,大多数数据绑定用途TypeDescriptor-不只是PropertyGrid
马克·格雷夫

1
在Silverlight项目中添加属性元数据属性的任何解决方法(在哪里TypeDescriptor以及TypeDescriptionProvider未实现?
Shimmy Weitzhandler 2012年

1
需要注意的重要一点是,TypeDescriptor.GetAttributes()不会处理重复的属性。它仅选择属性类型的最后一个。发现[Attr(1), Attr(2), Attr(3)]仅Ex Attr(3)
ohmusama

11

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


10

好吧,只是有所不同,我找到了一篇使用Reflection.Emit引用的文章。

这是链接:http : //www.codeproject.com/KB/cs/dotnetattributes.aspx,由于可能的方法已在讨论中,因此您还将希望查看本文底部的一些评论。


10
请注意,您可以在运行时使用Reflection.Emit类创建属性,但是可以将它们绑定到使用Emit包构建的类,而不是现有的类。
Panos

什么是无用的答案=))我们都在这里关心现有的类,而不是动态的类。
绝望的

@Hopeless,您可以将其子类YourClass化为YourRuntimeClassWithAttributes
微粒

@Motes不确定您的意思,我的类都是预先定义的,这意味着(我的类继承的)所有基类也应该事先定义/确定。我想不出任何方式将它与使用Reflection.Emit动态创建的东西相关联。
充满希望的

1
@Hopeless,如果您想向现有类动态添加属性YourClass,则可以在运行时对其进行子类化,并生成一个名称稍有不同的相同类,该类也具有所需的动态创建的属性,而多态性将允许类型检查代码仍然识别您的基类。
微粒

4

不,这不对。

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


3

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


22
TypeDescriptor.AddAttributes(Object,Attribute [])将类级别的属性添加到目标组件实例。
Peter Wone

3

如果您需要能够动态添加的内容,则不能使用c#属性。研究将数据存储在xml中。我最近做了一个项目,该项目以属性开始,但最终转移到以xml进行序列化。


1
也许这不是一个漂亮的方法,但是它是许多其他库选择使用的方法,并且要自定义这些库的行为,我们需要处理反射=))确实是一个死锁。
绝望的

3

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

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


1
消除样板。如果您可以让一个类根据该类中的代码自动生成属性,那会很方便吗?我试图找出类似的方法来减少SQL CLR对象中的样板。很容易在其他语言中...看到paulgraham.com/avg.html
邓肯贝恩

1

我非常尝试使用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);
                }
            }
        }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.