【问题标题】:Can attributes be added dynamically in C#?可以在 C# 中动态添加属性吗?
【发布时间】:2010-09-12 20:36:01
【问题描述】:

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

【问题讨论】:

标签: c# .net attributes


【解决方案1】:

我不相信。即使我错了,您最好的希望是将它们添加到整个 Type,而不是 Type 的 instance

【讨论】:

  • TypeDescriptor.AddAttributes(Object, Attribute[]) 将类级属性添加到目标组件实例。
【解决方案2】:

不,不是。

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 也许这不是一个漂亮的方式,但它是许多其他库选择使用的方式,并且要自定义这些库的行为,我们需要使用反射 =)) 确实是一个死锁。跨度>
        【解决方案6】:

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

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

        【讨论】:

        • 消除样板。如果您可以让一个类根据类中的代码自动生成属性,那不是很方便吗?我试图找出这样的东西来减少 SQL CLR 对象中的样板。用其他语言会很容易......见paulgraham.com/avg.html
        【解决方案7】:

        这真的取决于你到底想要完成什么。

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

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

        【讨论】:

        • 实际上,大多数数据绑定使用TypeDescriptor - 不仅仅是PropertyGrid
        • 在 Silverlight 项目中添加属性元数据属性的任何解决方法(TypeDescriptorTypeDescriptionProvider 未实现?
        • 需要注意的是,TypeDescriptor.GetAttributes() 不处理重复的属性。它只选择最后一个属性类型。例如 [Attr(1), Attr(2), Attr(3)] 仅找到 Attr(3)
        【解决方案8】:

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

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

        【讨论】:

        • 请注意,您可以在运行时使用 Reflection.Emit 类创建属性,但是您可以将它们绑定到使用 Emit 包构建的类,而不是现有的类。
        • 多么无用的答案 =)) 我们都关心这里的现有类,而不是动态类。
        • @Hopeless,您可以将YourClass 子类化为YourRuntimeClassWithAttributes
        • @Motes 不确定你的意思,我的类都是预先定义的,这意味着所有基类(我的类继承的)也应该预先定义/确定。我想不出任何办法让它参与使用 Reflection.Emit 动态创建的东西。
        • @Hopeless,如果您想将属性动态添加到现有类YourClass,您可以在运行时对其进行子类化并生成一个名称稍有不同的相同类,该类也具有所需的动态创建属性,并且多态性将允许类型检查代码仍然识别您的基类。
        【解决方案9】:

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

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

        【讨论】:

        • 链接失效,请删除您的回答
        【解决方案10】:

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

        【讨论】:

        • 使用这些方法,您可以将属性的值更改为单独的实体。 THE Pr​​operty的属性保持不变!
        • 这是可能的,事实上我已经做了一个动态对象(你可以在运行时添加/删除动态属性,我的代码很可能来自那个小库)。很抱歉。
        猜你喜欢
        • 1970-01-01
        • 2014-05-28
        • 1970-01-01
        • 2016-07-13
        • 2015-12-12
        • 2011-12-15
        • 1970-01-01
        • 1970-01-01
        • 2013-03-27
        相关资源
        最近更新 更多