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

问题描述 投票:0回答:10

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

c# .net attributes
10个回答
71
投票

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

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

据我所知,PropertyGrid 控件和 visual studio 设计图面是 BCL 中唯一使用 TypeDescriptor 内容的东西。事实上,他们真正需要做的事情中有一半就是这样做的。


69
投票

属性是静态元数据。程序集、模块、类型、成员、参数和返回值不是 C# 中的一流对象(例如,

System.Type
类仅仅是类型的反映表示)。您可以获得类型的属性实例并更改属性(如果它们是可写的)但不会影响属性,因为它应用于类型。


12
投票

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


11
投票

好吧,为了与众不同,我找到了一篇文章,其中提到使用 Reflection.Emit 来做到这一点。

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


4
投票

不,不是。

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


3
投票

我不这么认为。即使我错了,您也只能希望将它们添加到整个类型中,而不是类型的实例


3
投票

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


3
投票

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

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


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

0
投票

面对这种情况,另一种解决方案可能是质疑您的代码设计并寻找更面向对象的方式。对我来说,与不愉快的反射工作作斗争是最后的手段。而我对这种情况的第一反应是重新设计代码。想一想下面的代码,它试图解决您必须向正在使用的第三方类添加属性的问题。

class Employee {} // This one is third-party.

你有这样的代码

var specialEmployee = new Employee();
// Here you need an employee with a special behaviour and 
// want to add an attribute to the employee but you cannot.

解决方案可能是提取一个继承自

Employee
类的类并用您的属性装饰它:

[SpecialAttribute]
class SpecialEmployee : Employee 
{
}

当你创建这个新类的实例时

var specialEmployee = new SpecialEmployee();

您可以区分这个

specialEmployee
对象与其他
employee
对象。如果合适,您可能希望将此
SpecialEmployee
设为私有嵌套类。

© www.soinside.com 2019 - 2024. All rights reserved.