特性
1 什么是特性,如何自定义一个特性
2 .NET中特性可以在哪些元素上使用
3 有哪几种方法可以获知一个元素是否申明某个特性
4 一个元素是否可以重复申明同一个特性
特性是一种特殊的用以申明式编程的机制,特性类型是一族继承自System.Attribute的类型,在编译时,特性的使用会被写入元数据中,以共运行或者程序中的反射使用。自定义一个特性,本质上是定义一个继承自System.Attribute的类型。
自定义特性示例:
/// <summary> /// 自定义的特性 /// </summary> [AttributeUsage(AttributeTargets.Class)] public class MyAttribute : Attribute { private String _classname; public MyAttribute(String s) { _classname = s; } //一个只读属性 public String ClassName { get { return _classname; } } } /// <summary> /// 使用自定义属性 /// </summary> [MyAttribute("UseMyAttribute")] class UseMyAttribute { static void Main(string[] args) { Type t = typeof(UseMyAttribute); Object[] attributes = t.GetCustomAttributes(false); MyAttribute att = (MyAttribute)attributes[0]; Console.WriteLine(att.ClassName); Console.Read(); } }
输出:
UseMyAttribute
特性将被写入元数据中,所以特性的使用基本都基于反射机制。
有几点需要注意:
- 按照惯例,特性的名字都以Attribute结尾。
- C#中,为了使用方便,可以省略特性名字后缀Attribute,如 [MyAttribute("UseMyAttribute")] 可写为 [My("UseMyAttribute")]。
- 特性自身可以添加其他特性。
特性可以应用在程序集、模块、结构、枚举、构造方法、方法、属性、字段、事件、接口、参数、委托、返回参数和泛型参数这些目标元素上。通过AttributeUsage特性可以限制自定义特性的使用范围。
示例:
using System; //应用在程序集上 [assembly: MyAttribute] //应用在模块上 [module: MyAttribute] //应用在类型上 [type: MyAttribute] class AttributeTargets<[typevar: MyAttribute] T> //泛型参数上 { //应用在字段上 [field: MyAttribute] private String _MyString; //应用在构造方法上 [method: MyAttribute] public AttributeTargets() { } //应用在属性上 [property: MyAttribute] public String MyString { get { return _MyString; } } //应用在方法上 [return: MyAttribute] public String Format( //应用在方法参数上 [param: MyAttribute]String f) { return null; } //应用在事件上 [event: MyAttribute] public event EventHandler MyEvent; } /// <summary> /// 一个空的特性 /// 可用于所有元素 /// </summary> public class MyAttribute : System.Attribute { } public class MainClass { static void Main(string[] args) { } }
System.Attribute.IsDefined
System.Attribute.GetCustomAttribute
System.Attribute.GetCustomAttributes
System.Reflection.CustomAttributeData
示例:
[My("GetAttributes")] class GetAttributes { static void Main(string[] args) { Type attributeType = typeof(MyAttribute); Type thisClass = typeof(GetAttributes); //使用IsDefined方法 bool defined = Attribute.IsDefined( thisClass, attributeType); Console.WriteLine( "GetAttributes类型是否申明了MyAttribute特性:{0}", defined.ToString()); //使用Attribute.GetCustomAttribute方法 Attribute att = Attribute.GetCustomAttribute( thisClass, attributeType); if (att != null) { Console.WriteLine( "GetAttributes类型申明了MyAttribute特性。"); Console.WriteLine("名字为:{0}", ((MyAttribute)att).Name); } //使用Attribute.GetCustomAttributes方法 Attribute[] atts = Attribute.GetCustomAttributes( thisClass, attributeType); if (atts.Length > 0) { Console.WriteLine( "GetAttributes类型申明了MyAttribute特性。"); Console.WriteLine("名字为:{0}", ((MyAttribute)atts[0]).Name); } //使用System.Reflection.CustomAttributeData类型 IList<CustomAttributeData> list = CustomAttributeData.GetCustomAttributes(thisClass); if (list.Count > 0) { Console.WriteLine( "GetAttributes类型申明了MyAttribute特性。"); //注意这里可以对特性进行分析,但不能得到其实例 CustomAttributeData attdata = list[0]; Console.WriteLine("特性的名字是:{0}", attdata.Constructor.DeclaringType.Name); Console.WriteLine("特性的构造方法有{0}个参数。", attdata.ConstructorArguments.Count); } Console.Read(); } } /// <summary> /// 一个简单的特性 /// </summary> [AttributeUsage(AttributeTargets.All)] public sealed class MyAttribute : Attribute { private String _name; public MyAttribute(String s) { _name = s; } public String Name { get { return _name; } } }
输出:
GetAttributes类型是否申明了MyAttribute特性:True
GetAttributes类型申明了MyAttribute特性。
名字为:GetAttributes
GetAttributes类型申明了MyAttribute特性。
名字为:GetAttributes
GetAttributes类型申明了MyAttribute特性。
特性的名字是:MyAttribute
特性的构造方法有1个参数。
4 一个元素是否可以重复申明同一个特性
当一个特性申明了AttributeUsage特性并且显示地将AllowMultiple属性设置为true时,该特性就可以在同一元素上多次申明,否则的话编译器将被报错。
示例:
[My("Class1")] [My("Class2")] [My("Class1")] class AllowMultiple { static void Main(string[] args) { } } /// <summary> /// 使用AttributeUsage限定使用范围 /// 并且允许在同一元素上多次申明 /// </summary> [AttributeUsage(AttributeTargets.Class,AllowMultiple=true)] class MyAttribute : Attribute { private String _s; public MyAttribute(String s) { _s = s; } }
转载请注明出处: