如何在C#中创建自定义属性

sla*_*dhe 111 c# custom-attributes c#-4.0

我已经尝试了很多次,但我仍然无法理解自定义属性的用法(我已经经历了很多链接).

任何人都可以向我解释一个带代码的自定义属性的基本示例吗?

Dar*_*rov 252

首先编写一个派生自Attribute的类:

public class MyCustomAttribute: Attribute
{
    public string SomeProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以用这个属性装饰任何东西(类,方法,属性......):

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{

}
Run Code Online (Sandbox Code Playgroud)

最后你会用反射来获取它:

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value
}
Run Code Online (Sandbox Code Playgroud)

您可以使用AttributeUsage属性限制可以应用此自定义属性的目标类型:

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
Run Code Online (Sandbox Code Playgroud)

关于属性的重要事项:

  • 属性是元数据.
  • 它们在编译时被装入程序集,这对于如何设置其属性具有非常严重的影响.只接受常量(在编译时已知)值
  • 了解自定义属性的唯一方法是使用Reflection.因此,如果您不在运行时使用反射来获取它们并使用自定义属性装饰某些内容,那么预计不会发生太多事情.
  • 创建属性的时间是不确定的.它们由CLR实例化,你完全无法控制它.

  • 在哪个函数/类中,我应该使用反射来获取它 (3认同)

Bru*_*ant 92

虽然创建自定义属性的代码非常简单,但了解什么是属性非常重要:

属性是编译到程序中的元数据.属性本身不会向类,属性或模块添加任何功能,只会添加数据.但是,使用反射,可以利用这些属性来创建功能.

所以,举例来说,让我们来看看验证应用程序块,从企业库.如果你看一个代码示例,你会看到:

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
    public string Code { get; set; }
Run Code Online (Sandbox Code Playgroud)

从上面的代码片段中,人们可能会猜测,无论何时更改,代码将始终根据Validator的规则进行验证(在示例中,至少包含8个字符,最多8个字符).但事实是,属性不执行任何操作,只会向属性添加元数据.

但是,企业库有一个Validation.Validate方法可以查看您的对象,并且对于每个属性,它将检查内容是否违反了属性通知的规则.

因此,您应该如何考虑属性 - 一种向代码添加数据的方法,以后可能被其他方法/类/等使用.

  • 不知道为什么这是公认的答案.实际问题(也在Google中编入索引)是"如何在C#中创建*自定义属性".答案根本没有深入研究该主题.另一方面,第二个答案确实如此. (5认同)

Hop*_*per 22

利用/复制Darin Dimitrov的响应很好,这是如何访问属性而不是类的自定义属性:

装饰属性[类Foo]:

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }
Run Code Online (Sandbox Code Playgroud)

取得它:

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;
}
Run Code Online (Sandbox Code Playgroud)

您可以将其抛出循环并使用反射来访问类的每个属性上的此自定义属性Foo:

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    {
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    }
}
Run Code Online (Sandbox Code Playgroud)

非常感谢你,Darin !!