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

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

108322 次浏览

我不这么认为。即使我错了,你最好的希望是把他们加入到一个完整的类型,从来没有一个 例子的类型。

不,不是的。

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

你不能。一个解决方案可能是在运行时生成一个派生类并添加属性,尽管这可能有点夸张。

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

如果您需要能够动态添加的东西,那么 c # 属性不是解决方法。研究将数据存储在 xml 中。我最近做了一个项目,我启动了 w/Attribute,但最终转移到序列化 w/xml。

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

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

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

系统。组件模型。类型描述符可以用来为类型、属性和对象实例添加属性,它还有一个限制,即您必须使用它来检索这些属性。如果您正在编写使用这些属性的代码,并且您可以生活在这些限制之内,那么我肯定会建议您这样做。

据我所知,PropertyGrid 控件和可视化工作室设计图面是 BCL 中唯一使用 TypeDescriptor 的东西。事实上,这就是他们如何去做他们真正需要做的事情的一半。

为了与众不同,我找到了一篇引用使用反射的文章。

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

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

我非常努力的尝试与系统。组件模型。类型描述符失败。这并不意味着它不能工作,但我希望看到这方面的代码。

在对应部分,我想更改一些 Attribute 值。 我做了两个功能,工作良好,为此目的。

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