C#中的特性与反射
一、特性
特性是一个类,用来标记在某个元素上增加一定行为信息的声明性标签。一个声明性标签是通过放置在它所应用的元素前面的方括号[]来描述的。
预定义特性
Conditional:这个预定义特性标记了一个条件方法,用于在条件编译,如[Conditiaol("Debug")]
Obsolete:这个预定义特性标记了不应再使用的程序实体。如果iserror为true时,编译器将会生成一个错误,必须调用新的方法来替代
AttributeUsage这个预定义特性描述如何使用一个自定义特性类,如果有自定义特性类时,需要配合它实现相应的功能。
如何自定义特性
1、定义一个类,直接或间接继承于Attribute
2、约定俗成的以Attribute为后缀,但是这个是可选的
3、以Attribute结尾(为后缀的)的,使用的时候可以省略Attribute
4、标记-修饰:类及类内部的所有元素
5、默认不能重复标记,如果需要重复标记,需要设置AllowMultiple=true,默认是不被继承的,如果需要则设置inherited=true
特性的功能是通过反射来实现的
using System; using System.Reflection; namespace BugFixApplication { // 一个自定义特性 BugFix 被赋给类及其成员 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class DeBugInfo : System.Attribute { private int bugNo; private string developer; private string lastReview; public string message; public DeBugInfo(int bg, string dev, string d) { this.bugNo = bg; this.developer = dev; this.lastReview = d; } public int BugNo { get { return bugNo; } } public string Developer { get { return developer; } } public string LastReview { get { return lastReview; } } public string Message { get { return message; } set { message = value; } } } [DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")] [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")] class Rectangle { // 成员变量 protected double length; protected double width; public Rectangle(double l, double w) { length = l; width = w; } [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")] public double GetArea() { return length * width; } [DeBugInfo(56, "Zara Ali", "19/10/2012")] public void Display() { Console.WriteLine("Length: {0}", length); Console.WriteLine("Width: {0}", width); Console.WriteLine("Area: {0}", GetArea()); } }//end class Rectangle class ExecuteRectangle { static void Main(string[] args) { Rectangle r = new Rectangle(4.5, 7.5); r.Display(); Type type = typeof(Rectangle); // 遍历 Rectangle 类的特性 foreach (Object attributes in type.GetCustomAttributes(false)) { DeBugInfo dbi = (DeBugInfo)attributes; if (null != dbi) { Console.WriteLine("Bug no: {0}", dbi.BugNo); Console.WriteLine("Developer: {0}", dbi.Developer); Console.WriteLine("Last Reviewed: {0}", dbi.LastReview); Console.WriteLine("Remarks: {0}", dbi.Message); } } // 遍历方法特性 foreach (MethodInfo m in type.GetMethods()) { foreach (Attribute a in m.GetCustomAttributes(true)) { DeBugInfo dbi = (DeBugInfo)a; if (null != dbi) { Console.WriteLine("Bug no: {0}, for Method: {1}", dbi.BugNo, m.Name); Console.WriteLine("Developer: {0}", dbi.Developer); Console.WriteLine("Last Reviewed: {0}", dbi.LastReview); Console.WriteLine("Remarks: {0}", dbi.Message); } } } Console.ReadLine(); } } }
注意:上面在调用DeBugInfo dbi = (DeBugInfo)a;时会报错
System.InvalidCastException:“Unable to cast object of type 'System.Runtime.CompilerServices.NullableContextAttribute' to type 'testAttribute.DebugInfo'.”
需要修改为 foreach(MethodInfo info in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
因为默认调用的类中含有GetType(),GetHashCode(),ToString()及Equals()等方法