公共语言运行库允许添加类似关键字的描述性声明(称为属性 (Attribute))来批注编程元素,如类型、字段、方法和属性 (Property)。
为运行库编译代码时,该代码被转换为 Microsoft 中间语言 (MSIL),并同编译器生成的元数据一起被放到可移植可执行 (PE) 文件的内部。属性使您得以向元数据中放置额外的描述性信息,并可使用运行库反射服务提取该信息。当声明从 System.Attribute
派生的特殊类的实例时,编译器会创建属性。
编写自定义属性
自定义属性实质上是直接或间接地从 System.Attribute
派生的传统类。与传统类一样,自定义属性也包含存储和检索数据的方法。正确设计自定义属性类的主要步骤如下:
- 应用 AttributeUsageAttribute 
自定义属性声明以 AttributeUsageAttribute 开始,而该属性定义属性类的一些主要属性。例如,可指定属性是否可被其他类继承,或指定属性可应用到哪些元素。e.g. [AttributeUsage(AttributeTargets.All, Inherited = false,
AllowMultiple = true)]。System.AttributeUsageAttribute 包含三个对创建自定义属性具有重要意义的成员:AttributeTargets、Inherited 和 AllowMultiple。
 
AttributeTargets 成员:
AttributeTargets.All,指示该属性可以应用到所有程序元素;
AttributeTargets.Class,指示属性只可以应用于某个类;
AttributeTargets.Method,指示属性只可以应用于某个方法;
所有程序元素都可通过这种方式由自定义属性标记,以便对其进行描述。
 
继承属性:
Inherited
属性指示属性是否可由从该属性应用到的类派生的类继承。该属性采用
true(默认值)或 false 标志。
 
AllowMultiple 属性
AllowMultiple
属性指示元素中是否可存在属性的多个实例。如果设置为 true,则允许存在多个实例;如果设置为 false(默认值),则只允许存在一个实例。
 
如果 AllowMultiple 属性和 Inherited 属性都设置为 true,则从另一个类继承的类可以继承一个属性,并在同一子类中应用同一属性的另一个实例。如果 AllowMultiple 设置为 false,则父类中的所有属性值将被子类中同一属性的新实例覆盖。
 
声明属性类,注意一下几点:
  a)  属性类必须声明为公共类。
  b)  按照约定,属性类的名称以单词 Attribute 结尾。虽然并不要求这样,但出于可读性目的,建议采用此约定。应用属性时,可以选择是否包含 Attribute 一词。
  c)  所有属性类都必须直接或间接地从 System.Attribute 继承。
 
检索自定义属性信息
检索自定义属性的过程很简单。首先,声明要检索的属性实例。然后,使用 Attribute.GetCustomAttribute
方法将新属性初始化为要检索的属性值。初始化新属性后,只需使用其属性获取值即可。本主题描述如何检索已加载到执行上下文中的代码的属性。若要检索已加载到只反射上下文中的代码的属性,必须使用 CustomAttributeData 类。 
- 检索属性的一个实例
- 检索应用到同一范围的属性的多个实例,如果类级别上只应用属性的一个实例,则该代码将运行良好。但是,如果在同一类级别上应用属性的多个实例,则
GetCustomAttribute 方法不检索所有信息。如果同一个属性的多个实例应用到相同的范围,可使用 Attribute.GetCustomAttributes
将属性的所有实例放到一个数组中。
 3. 检索应用到不同范围的属性的多个实例,GetCustomAttributes 方法和
GetCustomAttribute 方法不搜索整个类和返回该类中某个属性的所有实例。相反,   它们一次只搜索一个指定方法或成员。如果将具有同一属性的某个类应用到每个成员,并要检索应用到这些成员的所有属性值,则必须向                 GetCustomAttributes 和
GetCustomAttribute 分别提供每个方法或成员。
示例:
属性类定义
 

 代码
代码
 1 [AttributeUsage(AttributeTargets.All)]
 2     public class DeveloperAttribute : System.Attribute
 3     {
 4         private string name;
 5         private string level;
 6         private bool reviewed;
 7 
 8         public DeveloperAttribute(string name, string level)
 9         {
10             this.name = name;
11             this.level = level;
12             this.reviewed = false;
13         }
14 
15         //Define Name property.
16         //This is a read-only attribute.
17  
18         public virtual string Name
19         {
20             get { return name; }
21         }
22 
23         //Define Level property.
24         //This is a read-only attribute.
25  
26         public virtual string Level
27         {
28             get { return level; }
29         }
30 
31         //Define Reviewed property. 
32         //This is a read/write attribute. 
33  
34         public virtual bool Reviewed
35         {
36             get { return reviewed; }
37             set { reviewed = value; }
38         }
39     }
 
属性类应用
 

 代码
代码
 1     [Developer("Joan Smith", "42", Reviewed = true)]
 2     public class DeveloperApp
 3     {
 4         public static DeveloperApp Instance
 5         {
 6             get
 7             {
 8                 return new DeveloperApp();
 9             }
10         }
11 
12         /// <summary>
13         /// 检索属性的一个实例
14         /// </summary>
15          public void GetAttribute()
16         {
17             DeveloperAttribute myAttribute = System.Attribute.GetCustomAttribute(this.GetType(), typeof(DeveloperAttribute)) as DeveloperAttribute;
18 
19             if (myAttribute == null)
20             {
21                 Console.WriteLine("The attribute is not found ");
");
22             }
23             else
24             {                
25                 Console.WriteLine("The Name Attribute is: {0}.", myAttribute.Name);                
26                 Console.WriteLine("The Level Attribute is: {0}.", myAttribute.Level);                
27                 Console.WriteLine("The Reviewed Attribute is: {0}.", myAttribute.Reviewed);
28             }
29         }
30 
31         /// <summary>
32         /// 检索应用到同一范围的属性的多个实例
33         /// </summary>
34         /// <param name="toClass">class-level</param>
35          public void GetAttribute(string class_level)
36         {
37             DeveloperAttribute[] myAttributes = System.Attribute.GetCustomAttributes(this.GetType(), typeof(DeveloperAttribute)) as DeveloperAttribute[];
38 
39             if (myAttributes == null)
40             {
41                 Console.WriteLine("The attribute is not found ");
");
42             }
43             else
44             {
45                 foreach (DeveloperAttribute myAttribute in myAttributes)
46                 {
47                     Console.WriteLine("The Name Attribute is: {0}.", myAttribute.Name);
48                     Console.WriteLine("The Level Attribute is: {0}.", myAttribute.Level);
49                     Console.WriteLine("The Reviewed Attribute is: {0}.", myAttribute.Reviewed);
50                 }
51             }
52         }
53 
54         public void GetAttribute(string class_level, string method_level)
55         {
56             GetAttribute();//class_level
57  
58             DeveloperAttribute developerAtt;
59             MemberInfo[] member = this.GetType().GetMethods();
60 
61             foreach (MemberInfo obj in member)
62             {
63                 developerAtt = System.Attribute.GetCustomAttribute(obj, typeof(DeveloperAttribute)) as DeveloperAttribute;
64                 if (null == developerAtt)
65                 {
66                     Console.WriteLine("No attribute in member function {0}.\n", obj.ToString());
67                 }
68                 else
69                 {
70                     Console.WriteLine("The Name Attribute for the {0} member is: {1}.", obj.ToString(), developerAtt.Name);
71                     Console.WriteLine("The Level Attribute for the {0} member is: {1}.", obj.ToString(), developerAtt.Level);
72                     Console.WriteLine("The Reviewed Attribute for the {0} member is: {1}.\n",obj.ToString(), developerAtt.Reviewed);
73                 }       
74             }
75         }
76     } 
 
 
自定义属性检索的三个方法比较
- IsDefined:当至少有一个指定的属性类(实例)与目标相关联时,返回true。此方法效率最高,因为它不构造(反序列化)属性类的实例。
- GetCustomeAttributes:返回应用于目标的属性类(实例)数组。对于AllowMultiple设为true的属性,一般应使用此方法。
- GetCustomeAttribute:返回应用于目标的属性类(实例)。若目标没有应用属性类,则返回null,对于应用了多个AllowMultiple=false的属性,会出现System.Reflection.AmbiguousMatchException 异常。