C# 特性(Attributes) 浅解

291 阅读3分钟

概述

C#中的特性(Attributes)能够将额外的描述性信息放到可使用运行时反射服务提取的元数据中。当声明派生类System.Attribute的特殊类的实例时,编译器会创建特性,编译代码时,特性将被发放到元数据中,并且通过运行反射服务可用于公共语言运行时和任何自定义工具或应用程序。

应用特性

所有特性名称都以"Attribute"结尾,但使用时无需指定特性的全称。例如,若要初始化System.ObsoleteAttribute,只需要将它引用为Obsolete即可。

  • 应用于方法
public class Example{
    [Obsolete("Will be removed in next version)]
    public static int Add(int a, int b){
        return (a + b);
    }
}
			  
class Test{
    public static void Main(){
        // 这行代码会抛出一个编译警告
        int i = Example.Add(2, 2);
    }
}
  • 在程序集应用特性
using System.Reflection
[assembly:AssemblyTitle("My Assembly")]

编写自定义特性

自定义属性就是设计一个直接或间接派生字System.Attribute类的传统类。和传统类一样,自定义特性包含用于存储和检索数据的方法。

  • 应用AttributeUsageAttribute
    自定义属性声明以AttributeUsageAttribute属性开头,定义特性类的一些主要特征。例如,你可以指定其他类是否继承你的属性,或者此属性可以应用到哪些元素。
    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
    
    AttributeUsageAttribute 包含三个属性,分别是AttributeTargetsInheritedAllowMultiple
    • AttributeTargets属性
      AttributeTargets.All表示此属性可用于所有程序元素
      AttributeTargets.Class表示此属性适用于一个类
      AttributeTargets.Method表示此属性适用于一个方法
      并且你可以组合多个AttributeTargets值。
      [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
      
      具体信息查看AttributeTargets类文档
    • Inherited属性
      AttributeUsageAttribute.Inherited属性指明要对其应用属性的类的的派生类能否继承。此属性默认值为true
      // this defaults to Inherited = true.
      public class MyAttribute : Attribute{
      	// ...
      }
      
      [AttributeUsage(AttributeTargets.Method, Inherited = false)]
      public class YourAttribute : Attribute{
      	// ...
      }
      
      // 将两个特性应用于MyClass
      public class MyClass{
      	[MyAttribute]
      	[YourAttribute]
      	public virtual void Mythod(){
      		// ...
      	}
      }
      
      // YourClass继承MyClass。方法MyMetho只显示MyAttribute
      public class YourClass : MyClass{
      	// MyMethod will have MyAttribute but not YourAttribute.
      	public override void MyMethod(){
      		// ...
      	}
      }
      
    • AllowMultiple属性
      AttributeUsageAttribute.AllowMultiple属性指明元素能否包含属性的多个实例。如果设置为true,则允许多个实例,反之只允许一个实例。默认值为false
      // This defaults to AllowMultiple = false
      public class MyAttribute : Attribute{
      }
      
      [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
      public class YourAttribute : Attribute{
      }
      
      // 当应用MyAttribute的多个实例时会生成编译器错误。
      pubic class MyClass{
      	// this produces an compile error.
      	[MyAttribute]
      	[MyAttribute]
      	public void MyMethed(){
      	}
      	
      	// this is vaild
      	[YourAttribute]
      	[YourAttribute]
      	public void YourMethod(){
      	}
      }
      
  • 声明特性类
    [AttributeUsage(AttributeTarget.Method)]
    public class MyAttribute : Attribute{
    	// ...
    }
    
    • 特性必须声明为公共类
    • 特性名称以单词Attribute结束
    • 所有特性类直接或间接继承System.Attribute继承
  • 声明构造函数 和传统类一样,特性通过构造函数初始化,并且可以重载构造函数以适应值的各种组合。如果你还为自定义特性类定义了属性,则初始化该特性时可以作为可选参数传入。
    [AttributeUsage(AttributeTargets.All)]
    public class DeveloperAttribute : Attribute
    {
        // Private fields.
        private string name;
        private string level;
        private bool reviewed;
    
        // This constructor defines two required parameters: name and level.
        public DeveloperAttribute(string name, string level)
        {
            this.name = name;
            this.level = level;
            this.reviewed = false;
        }
    
        // Define Name property.
        // This is a read-only attribute.
        public virtual string Name
        {
            get {return name;}
        }
    	
        // Define Level property.
        // This is a read-only attribute.
        public virtual string Level
        {
            get {return level;}
        }
    
        // Define Reviewed property.
        // This is a read/write attribute.
        public virtual bool Reviewed
        {
            get {return reviewed;}
            set {reviewed = value;}
        }
    }
    
    // 仅应用必须的参数
    [Developer("Joan Smith", "1")]
    // 同时应用必选参数和可选参数
    [Developer("Joan Smith", "1", Reviewed = true)]
    

检索存储在特性中的信息

// 检测一个属性实例
DeveloperAttribute myAttribute = (DeveloperAttribute) Attribute.GetCustomAttribute(t, typeod(DeveloperAttribute));
if (MyAttribute == null) { 
	Console.WriteLine("The attribute was not found."); 
} else { 
	// Get the Name value. 
	Console.WriteLine("The Name Attribute is: {0}." , MyAttribute.Name); 
	// Get the Level value. 
	Console.WriteLine("The Level Attribute is: {0}." , MyAttribute.Level); 
	// Get the Reviewed value. 
	Console.WriteLine("The Reviewed Attribute is: {0}." , MyAttribute.Reviewed); 
}

// 检索应用于同一范围的多个属性实例
DeveloperAttribute[] MyAttributes = (DeveloperAttribute[]) Attribute.GetCustomAttributes(t, typeof (DeveloperAttribute));
if (MyAttributes.Length == 0) { 
	Console.WriteLine("The attribute was not found."); 
} else { 
	// ... 
}

//检索应用于不同范围的多个属性实例
MemberInfo[] MyMemberInfo = t.GetMethods();
for (int i = 0; i < MyMemberInfo.Length; i++) { 
	att = (DeveloperAttribute) Attribute.GetCustomAttribute(MyMemberInfo[i], typeof (DeveloperAttribute)); 
	if (att == null) { 
		Console.WriteLine("No attribute in member function {0}.\n" , MyMemberInfo[i].ToString()); 
	}else{
		// ...
	}
}