C#特性学习与使用

C#特性之前的时候,用过C#中的特性,但只是会用,什么原理,有什么用这些问题不清楚,今天就腾出时间,学习了一下。html

  C#中的特性使用Attribute描述。在使用时,就像是java中的批注同样。不过C#使用中括号。特性用来描述咱们的数据。编译器可以识别这些特性,以附加信息的形式存放在生成的元数据中,供clr使用。java

  下边看一个简单的应用view plainprint?数组

  static void Main(string[] args)ide

  { DisplayRunningMsg();DisplayDebugMsg();Trace("方法执行到结尾了!!");Console.Read();函数

  } [DllImport("User32.dll")] public static extern int MessageBox(int hParent, string msg, string Caption, int type);[Conditional("DEBUG")] private static void DisplayRunningMsg()学习

  { Console.WriteLine("This is debug");Console.WriteLine("开始运行Main子程序。当前时间是"+DateTime.Now);}this

  [Conditional("DEBUG")] [Obsolete] private static void DisplayDebugMsg()debug

  { Console.WriteLine("该方法已经废弃啦!!!");}调试

  DllImport特新容许咱们引入一个外部的dll,下边作一个函数的声明,咱们就能够调用了。htm

  Conditional属性表示在该种条件下就执行下边的代码 因此[Conditional("DEBUG")]此种标识的方法就只有在调试的时候才会在执行。 [Obsolete]特性标记该方法已经废弃。

  运行上述代码输出(在debug模式下)

  看的出来程序执行了[Conditional("DEBUG")]标记的方法。若是咱们debug改成release,那么再次执行

  程序并无执行上述方法。看的出来,因为特性[Conditional("DEBUG")]标记,是的在release模式下,代码并无运行其标记的函数。那么,咱们就能够利用这个作一个error trace,使其只在debug的模式下输出当前错误信息,包括行号,,方法名,位置等。这里要用到 stacktrace类。

  Ok,说到这里,你应该对特性有了以最最基本的了解。

  那么,究竟什么是特性呢?

  其实特性也是一个类。好比[Conditional("DEBUG")],就是构造了以Conditional对象(调用构造方法public Conditional(string type), 对,DllImport("User32.dll")对应的也有一个类DllImport.下边咱们自定义一个特性,你就会明白不少。

  首先须要定一个一个类 ,该类须要集成Attribute,使其成为一个特性……NET约定特性类都已Attribute结尾。而后在该类中定义一下字段和属性,完成构造。

 代码以下view plainprint?

  [AttributeUsage(AttributeTargets.All,AllowMultiple = true,Inherited = true)] class TrackerAttribute:Attribute {

  private string opUsername;private string opName;private DateTime dateTime;private string note;

  public TrackerAttribute(string opUsername,string opName,string date)

  { this.opUsername = opUsername;this.opName = opName;this.dateTime = DateTime.Parse(date);}

  //位置参数,经过构造函数传递值public string OpUsername { get { return opUsername; } }

  public string OpName { get { return opName; } }

  public DateTime DateTime { get { return dateTime; } }

  //命名参数,提供set public string Note { get { return note; } set { note = value; } }

  public override string ToString()

  { return "操做人" + opUsername + "操做名" + opName + "时间" + dateTime + "备注" + note;}

  嗯,对,他和普通的类几乎没什么差异,只不过继承于Attribute.而后他自己又有一些特性。咱们作逐一介绍咱们在类TrackerAttribute 定义了几个字段,完成了构造函数TrackerAttribute(string opUsername,string opName,stringdate)

  那么我么在使用的时候就须要写[Tracker(“opusername”,“opname”,“2011-10-2600:04”,note=“这是备注”)],嗯,是的,使用类型(参数值,参数值)的方法完成了该对象的构造,即调用了该类的构造函数。构造函数里与字段对应的参数叫作位置参数,由于写的时候必须位置一一与源构造函数相同,其余不经过构造函数传入参数传递的,叫作命名参数,使用字段名=字段值 的形式赋值。这样完成函数构造和一些属性的赋值。通常状况下,咱们将位置参数提供get访问,而命名参数则提供get和set,由于位置参数已经可以同感哦构造函数访问赋值了。

  这个特性类上边还有几个特性,AttributeTargets表示当前特性的做用范围,他是一个位标记的枚举,好比all,field,method,标记事后,智能在相应的地方作该特性书写。好比指定枚举是做用与字段,那么若是该特性写在类上边,就会报错。

  如上,你的特性类就完成了。

  这样你就能够在其余方法上作该特性的标记了。

  咱们定义了特性,最重要的仍是要得到该特性中的值。下边是得到的方法view plainprint?

  Type type = typeof(Program);object[] objects = type.GetCustomAttributes(false);foreach (var o in objects)

  { TrackerAttribute trackerAttribute = o as TrackerAttribute;if (trackerAttribute != null)

  Console.WriteLine(trackerAttribute.ToString());else { Console.WriteLine("得到对象为空");}

  type.GetCustomAttributes(false);该方法将会得到该类上的全部特性标记,返回的是一个object的数组,你能够遍历,而后转换为你的指定特性,访问相应字段便可。一样,你也能够经过type.getMethods()[0] 得到一个methodinfo对象,而后调用该methodinfo对象的GetCustomAttributes方法便可。

  介绍了如上的这些,咱们利用特性,实现为枚举增长一个得到其描述的功能。

  例如定义枚举MyEnummyenum=MyEnum.TypeA 调用myenum.ToDescription 能够获得字符串 类型A.咱们能够想到定一个描述特性,而后在各个枚举元素上,作该特性的标记,而后提供扩展方法,访问该特性,取得该特性值。

  代码以下枚举定义view plainprint?

  public enum MyType { [Description("A类型")] TypeA,[Description("B类型")] TypeB,[Description("C类型")] TypeC }

  特性类DescriptionAttribute定义以下view plainprint?

  [AttributeUsage(AttributeTargets.Field,AllowMultiple =true,Inherited = true)] class DescriptionAttribute:Attribute { private string description;public string Description { get { return description; } }

  public DescriptionAttribute(String description)

  { this.description = description;}

  指定该特性只用于字段,定义DescriptionAttribute(String description)构造函数。

  Ok,如今还缺乏枚举的ToDescription方法,C#中的枚举是不支持定义方法的。

  咱们能够为其作一个扩展方法扩展方法须要一个静态类,参数前要加this ,同时也指定了被扩展的对象,调用时可以使用扩展对像的实例调用,也可使用该静态类来调用。详细内容可参考http://www.cnblogs.com/sunrack/articles/1073759.html

  扩展类以下view plainprint?

  public static class Extension {

  public static string ToDescription(this MyType myEnum)

  { Type type = typeof (MyType);FieldInfo info= type.GetField(myEnum.ToString());DescriptionAttribute descriptionAttribute= info.GetCustomAttributes(typeof (DescriptionAttribute), true)[0] as DescriptionAttribute;if (descriptionAttribute != null)

  return descriptionAttribute.Description;else return type.ToString();}

  这样MyType就多了一个ToDescription的方法,返回的值就是对应的特性值。

  在main方法中MyTypemyType = MyType.TypeB;Console.WriteLine(myType.ToDescription());控制台输出 B类型 达到了咱们想要的效果。

  这个方法仍是颇有用的。

  从上边能够看出,咱们若是要为一些类添加一些附加的信息,1. 这些附加信息在现实意义与该对象并非具备真正的对象与属性关系,2. 没法在原来的,里边添加字段,或者加入字段后很难处理。这两种状况之一,均可以使用特性。随后,在IL中看一下,掉用特性时,编译器都作了什么事。

相关文章
相关标签/搜索