Attribute的妙用 ---- 攔截器(過濾器)

1、何爲Attribute

下面是微軟官方對Attribute的解釋:html

公共語言運行時容許你添加相似關鍵字的描述聲明,叫作Attributes,它對程序中的元素進行標註,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數據保存在一塊兒,能夠用來向運行時描述你的代碼,或者在程序運行的時候影響應用程序的行爲。函數

通俗地理解,就是對目標對象(程序集、類、方法等)進行擴展,使得在運行時能夠獲取到被擴展對象的額外的信息,經過額外的信息來影響目標對象的行爲。上面這句話純粹是我的的理解,若有不妥但願指教。post

2、使用Attribute

如今我有一個需求,建立一個包含 三個靜態方法的類,若是某個方法被打上了標籤,而且標籤的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指定的目標也是靜態方法),而後獲取方法上的自定義標籤集合,至關於方法的額外的信息,經過這些額外的信息來影響方法的執行,如今再回頭看看第一小節的粗體部分:

就是對目標對象(程序集、類、方法等)進行擴展,使得在運行時能夠獲取到被擴展對象的額外的信息,經過額外的信息來影響目標對象的行爲。

 以上是我的比較淺薄的理解,若是您有更深層次的理解,歡迎討論,互相學習。

 3、本身寫攔截器

根據上面的表述,結合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

相關文章
相關標籤/搜索