Attributes in C# 笔记
使用预定义的Attribute
using System; public class AnyClass { [Obsolete("Don't use Old method, use New method", true)] static void Old( ) { } static void New( ) { } public static void Main( ) { Old( ); } }
这里告诉编译器Old这个item是过时的,编译时会将它作为一个错误处理,并且显示信息:"别用老方法了,用新的方法吧".
自定义Attribute
只需要从System.Attribute类派生出来就可以了。
using System; public class HelpAttribute : Attribute { }
类的名字一般以Attribute作为词缀,但是不加也可以。当你使用Help进行修饰的时候,编译器会在Attribute派生类里寻找Help类,如果没有,就自动添加Attribute词缀,即:编译器会在子类里寻找HelpAttribute类。
接下来就是将HelpAttribute进行实现并装饰其他的类了。
using System; public class HelpAttribute : Attribute { public HelpAttribute(String Descrition_in) { this.description = Description_in; } protected String description; public String Description { get { return this.description; } } }
[Help("this is a do-nothing class")] public class AnyClass { }
AttributeUsage是一个特别的类,它修饰自定义的Attribute类,主要是帮助我们定义如何使用attribute,它有三个属性:
ValidOn可以指明attribute可以放在什么地方;AllowMultiple指明一个attribute是否可以多次放在同一个实体里面,Inherited指明这个attribute是否会在所修饰的类
的子类里面出现。
using System; [AttributeUsage(AttributeTargets.Class), AllowMultiple = false, Inherited = false ] public class HelpAttribute : Attribute { public HelpAttribute(String Description_in) { this.description = Description_in; } protected String description; public String Description { get { return this.description; } } }
这个例子说明,HelpAttribute只能修饰class,并且只能放一次,不能被继承。因此,下面的情况都是错的:
[Help("this is a do-nothing class")] public class AnyClass { [Help("this is a do-nothing method")] //只能修饰class,不能修饰方法 public void AnyMethod() { } } [Help("this is a do-nothing class")] [Help("it contains a do-nothing method")] //只能修饰一次而已,这里修饰了两次 public class AnyClass { public void AnyMethod() { } }
AttributeTargets包括:
- Assembly,
- Module,
- Class,
- Struct,
- Enum,
- Constructor,
- Method,
- Property,
- Field,
- Event,
- Interface,
- Parameter,
- Delegate,
- All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate,
- ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface
Positional Parameter和Named Parameter
Positional参数是构造器的参数,而且是强制要有的,相反,Named参数是可选的。
对于Named参数,如果要使用它,必须要定义一个set方法。
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class HelpAttribute : Attribute { public HelpAttribute(String Description_in) { this.description = Description_in; this.verion = "No Version is defined for this class"; } protected String description; public String Description { get { return this.description; } } protected String version; public String Version { get { return this.version; } //if we ever want our attribute user to set this property, //we must specify set method for it set { this.verion = value; } } } [Help("This is Class1")] public class Class1 { } [Help("This is Class2", Version = "1.0")] public class Class2 { } [Help("This is Class3", Version = "2.0", Description = "This is do-nothing class")] public class Class3 { }
这里的Description就是Positional参数,而Version就是Named参数。
Class 1和Class 2 都能正常输出,Class 3由于没有给Description的set方法,因此会报错Description为只读。
Attribute identifier
attribute identifier是用来标注attribute作用在什么上面,比如是方法上,类型上,返回值上还是全部的程序集上。
所有可能的值包括:
- assembly
- module
- type
- method
- property
- event
- field
- param
- return
于是就可以用[assembly: Help("this a do-nothing assembly")]指明Help作用在整个程序集上。
在运行时使用反射的方法查找一个类(或者一个方法,一个字段,整个程序集)上面所有的attribute
using System; using System.Reflection; using System.Diagnostics; //attaching Help attribute to entire assembly [assembly : Help("This Assembly demonstrates custom attributes creation and their run-time query.")] //our custom attribute class public class HelpAttribute : Attribute { public HelpAttribute(String Description_in) { // // TODO: Add constructor logic here this.description = Description_in; } protected String description; public String Description { get { return this.deescription; } } } //attaching Help attribute to our AnyClass [HelpString("This is a do-nothing Class.")] public class AnyClass { //attaching Help attribute to our AnyMethod [Help("This is a do-nothing Method.")] public void AnyMethod() { } //attaching Help attribute to our AnyInt Field [Help("This is any Integer.")] public int AnyInt; } class QueryApp { public static void Main() { HelpAttribute HelpAttr; //Querying Assembly Attributes String assemblyName; Process p = Process.GetCurrentProcess(); assemblyName = p.ProcessName + ".exe"; Assembly a = Assembly.LoadFrom(assemblyName); foreach (Attribute attr in a.GetCustomAttributes(true)) { HelpAttr = attr as HelpAttribute; if (null != HelpAttr) { Console.WriteLine("Description of {0}:\n{1}", assemblyName,HelpAttr.Description); } } Type type = typeof(AnyClass); //Querying Class Attributes foreach (Attribute attr in type.GetCustomAttributes(true)) { HelpAttr = attr as HelpAttribute; if (null != HelpAttr) { Console.WriteLine("Description of AnyClass:\n{0}", HelpAttr.Description); } } //Querying Class-Method Attributes foreach(MethodInfo method in type.GetMethods()) { foreach (Attribute attr in method.GetCustomAttributes(true)) { HelpAttr = attr as HelpAttribute; if (null != HelpAttr) { Console.WriteLine("Description of {0}:\n{1}", method.Name, HelpAttr.Description); } } } //Querying Class-Field (only public) Attributes foreach(FieldInfo field in type.GetFields()) { foreach (Attribute attr in field.GetCustomAttributes(true)) { HelpAttr= attr as HelpAttribute; if (null != HelpAttr) { Console.WriteLine("Description of {0}:\n{1}", field.Name,HelpAttr.Description); } } } } }