下面是微軟官方對Attribute的解釋:html
公共語言運行時容許你添加相似關鍵字的描述聲明,叫作Attributes,它對程序中的元素進行標註,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數據保存在一塊兒,能夠用來向運行時描述你的代碼,或者在程序運行的時候影響應用程序的行爲。函數
通俗地理解,就是對目標對象(程序集、類、方法等)進行擴展,使得在運行時能夠獲取到被擴展對象的額外的信息,經過額外的信息來影響目標對象的行爲。上面這句話純粹是我的的理解,若有不妥但願指教。post
如今我有一個需求,建立一個包含 三個靜態方法的類,若是某個方法被打上了標籤,而且標籤的Flag是1,那麼就執行該方法,不然就不執行。看起來有點像過濾器,那麼如何來實現這個小需求呢?首先要建立一個靜態類MethodToRun,該類有三個靜態方法分別是Run、Walk、Go,代碼以下:學習
1 public class MethodToRun 2 { 3 public static void Run () 4 { 5 Console.WriteLine("Run Run Hurry Up!"); 6 Console.ReadLine(); 7 } 8 9 public static void Walk() 10 { 11 Console.WriteLine("Walk Slowly~"); 12 Console.ReadLine(); 13 } 14 15 public static void Go() 16 { 17 Console.WriteLine("Go Go Go!"); 18 Console.ReadLine(); 19 } 20 }
好了,有了以上的類,接下來開始建立咱們自定義的Attribute,爲了和Property屬性作個區分,我稱之爲特性。取個名字叫ExcuteAttribute,擁有一個Flag屬性,代碼以下:this
1 [AttributeUsage(AttributeTargets.Method)] 2 public class ExcuteAttribute : Attribute 3 { 4 public int Flag { get; set; } 5 }
上述代碼第一行指定了該特性做用的範圍,回頭看下咱們以前說的一句話:spa
就是對目標對象(程序集、類、方法等)進行擴展,使得在運行時能夠獲取到被擴展對象的額外的信息,經過額外的信息來影響目標對象的行爲。code
這裏的AttributeUsage中的參數AttributeTargets就是目標對象,它是一個枚舉類型,具體的枚舉以下:htm
1 //指定能夠對它們應用屬性的應用程序元素。 2 [ComVisible(true)] 3 [Flags] 4 public enum AttributeTargets 5 { 6 //能夠對程序集應用屬性。 7 Assembly = 1, 8 9 //能夠對模塊應用屬性。 10 Module = 2, 11 12 //能夠對類應用屬性。 13 Class = 4, 14 15 //能夠對結構應用屬性,即值類型。 16 Struct = 8, 17 18 //能夠對枚舉應用屬性。 19 Enum = 16, 20 21 //能夠對構造函數應用屬性。 22 Constructor = 32, 23 24 //能夠對方法應用屬性。 25 Method = 64, 26 27 //能夠對屬性 (Property) 應用屬性 (Attribute)。 28 Property = 128, 29 30 //能夠對字段應用屬性。 31 Field = 256, 32 33 //能夠對事件應用屬性。 34 Event = 512, 35 36 //能夠對接口應用屬性。 37 Interface = 1024, 38 39 //能夠對參數應用屬性。 40 Parameter = 2048, 41 42 //能夠對委託應用屬性。 43 Delegate = 4096, 44 45 //能夠對返回值應用屬性。 46 ReturnValue = 8192, 47 48 //能夠對泛型參數應用屬性。 49 GenericParameter = 16384, 50 51 //能夠對任何應用程序元素應用屬性。 52 All = 32767 53 }
標籤建立完成了,咱們修改一下MethodToRun這個類,加上標籤,代碼以下:對象
public class MethodToRun { [Excute(Flag =1)] public static void Run () { Console.WriteLine("Run Run Hurry Up!"); Console.ReadLine(); } public static void Walk() { Console.WriteLine("Walk Slowly~"); Console.ReadLine(); } [Excute(Flag =2)] public static void Go() { Console.WriteLine("Go Go Go!"); Console.ReadLine(); } }
其中,Run方法和Go方法加上了標籤,且Flag的值分別爲1和2,咱們的需求是貼了標籤而且Flag爲1的方法被執行,下面來看下關鍵的調用代碼:blog
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //獲取MethodToRun類的靜態方法集合 6 MethodInfo[] methods = typeof(MethodToRun).GetMethods(BindingFlags.Public|BindingFlags.Static); 7 foreach (var method in methods) 8 { 9 MethodInfo info = method; 10 //獲取每一個方法上的Attributes集合 11 var attributes = info.GetCustomAttributes(typeof(Attribute), false); 12 13 foreach (var attri in attributes) 14 { 15 //若是自定義的標籤是指定的標籤則符合條件 16 if(attri is ExcuteAttribute) 17 { 18 ExcuteAttribute exe = attri as ExcuteAttribute; 19 //執行Flag爲1的方法 20 if(exe.Flag == 1) 21 { 22 info.Invoke(null, null); 23 } 24 } 25 } 26 } 27 Console.ReadLine(); 28 } 29 }
運行結果:
整個過程就是經過反射獲取目標集合,本例子中的MethodToRun類中的靜態方法(由於標籤都貼在了靜態方法中,且AttributeTargets指定的目標也是靜態方法),而後獲取方法上的自定義標籤集合,至關於方法的額外的信息,經過這些額外的信息來影響方法的執行,如今再回頭看看第一小節的粗體部分:
就是對目標對象(程序集、類、方法等)進行擴展,使得在運行時能夠獲取到被擴展對象的額外的信息,經過額外的信息來影響目標對象的行爲。
以上是我的比較淺薄的理解,若是您有更深層次的理解,歡迎討論,互相學習。
根據上面的表述,結合ASP.NET MVC經常使用的攔截器功能,本身實現一個極簡的攔截器。首先定義一個接口ICustomFilter,包含兩個接口方法,OnBeforeAction和OnAfterAction,代碼以下:
1 /// <summary> 2 /// 自定義攔截器 3 /// </summary> 4 public interface ICustomFilter 5 { 6 //Action執行以前執行 7 void OnBeforeAction(); 8 9 //Action執行以後執行 10 void OnAfterAction(); 11 }
再定義一個Attribute實現該接口:
1 public class CustomFilterAttribute : Attribute, ICustomFilter 2 { 3 public void OnAfterAction() 4 { 5 Console.WriteLine("Action 執行以後進行攔截!"); 6 } 7 8 public void OnBeforeAction() 9 { 10 Console.WriteLine("Action 執行以前進行攔截!"); 11 } 12 }
準備工做完成了,接下來給目標方法打上標籤,修改下MethodToRun中的代碼:
public class MethodToRun { [Excute(Flag =1)] public static void Run () { Console.WriteLine("Run Run Hurry Up!"); Console.ReadLine(); } [CustomFilter] public static void Walk() { Console.WriteLine("Walk Slowly~"); Console.ReadLine(); } [Excute(Flag =2)] public static void Go() { Console.WriteLine("Go Go Go!"); Console.ReadLine(); } }
其中Walk方法添加了[CustomAttribute]特性,接下來看下調用代碼是如何實如今Walk執行先後分別執行OnBeforeAction和OnAfterAction方法的,代碼以下:
class Program { static void Main(string[] args) { MethodInfo[] methods = typeof(MethodToRun).GetMethods(BindingFlags.Public|BindingFlags.Static); foreach (var method in methods) { MethodInfo info = method; var attributes = info.GetCustomAttributes(typeof(Attribute), false); foreach (var attri in attributes) { if(attri is ExcuteAttribute) { ExcuteAttribute exe = attri as ExcuteAttribute; if(exe.Flag == 1) { //info.Invoke(null, null); } } //這裏是重點 if(attri is CustomFilterAttribute) { CustomFilterAttribute cust = attri as CustomFilterAttribute; cust.OnBeforeAction(); info.Invoke(null, null); cust.OnAfterAction(); } } } Console.ReadLine(); } }
如今跑一下看看效果
上述小例子只是一個小小的應用,在.Net體系中,Attribute隨處可見,其應用範圍十分普遍。
出處:http://www.cnblogs.com/xhb-bky-blog/p/7840265.html