Attribute在.net編程中的應用整理(一)

Attribute的基本概念 經常有朋友問,Attribute是什麼?它有什麼用?好像沒有這個東東程序也能運行。實際上在.Net中,Attribute是一個非常重要的組成部分,爲了幫助大家理解和掌握Attribute,以及它的使用方法,特地收集了幾個Attribute使用的例子,提供給大家參考。在具體的演示之前,我想先大致介紹一下Attribute。我們知道在類的成員中有property成員,二者在中文中都做屬性解釋,那麼它們到底是不是同一個東西呢?從代碼上看,明顯不同,首先就是它們的在代碼中的位置不同,其次就是寫法不同(Attribute必須寫在一對方括符中)。什麼是Atrribute 首先,我們肯定Attribute是一個類,下面是msdn文檔對它的描述:公共語言運行時允許你添加類似關鍵字的描述聲明,叫做attributes, 它對程序中的元素進行標註,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數據保存在一起,可以用來向運行時描述你的代碼,或者在程序運行的時候影響應用程序的行爲。在.NET中,Attribute被用來處理多種問題,比如序列化、程序的安全特徵、防止即時編譯器對程序代碼進行優化從而代碼容易調試等等。下面,我們先來看幾個在.NET中標準的屬性的使用,稍後我們再回過頭來討論Attribute這個類本身。(文中的代碼使用C#編寫,但同樣適用所有基於.NET的所有語言) Attribute作爲編譯器的指令在C#中存在着一定數量的編譯器指令,如:#define DEBUG, #undefine DEBUG, #if等。這些指令專屬於C#,而且在數量上是固定的。而Attribute用作編譯器指令則不受數量限制。比如下面的三個Attribute: Conditional:起條件編譯的作用,只有滿足條件,才允許編譯器對它的代碼進行編譯。一般在程序調試的時候使用。 DllImport:用來標記非.NET的函數,表明該方法在一個外部的DLL中定義。 Obsolete:這個屬性用來標記當前的方法已經被廢棄,不再使用了。下面的代碼演示了上述三個屬性的使用: 

  1. #define DEBUG //這裏定義條件   
  2.   
  3.        
  4.   
  5. using System;   
  6.   
  7. using System.Runtime.InteropServices;   
  8.   
  9. using System.Diagnostics;   
  10.   
  11.        
  12.   
  13. namespace AttributeDemo   
  14.   
  15. {   
  16.   
  17.    class MainProgramClass   
  18.   
  19.    {   
  20.   
  21.     
  22.   
  23.       [DllImport("User32.dll")]   
  24.   
  25.       public static extern int MessageBox(int hParent, string Message, string Caption, int Type);   
  26.   
  27.         
  28.   
  29.       static void Main(string[] args)   
  30.   
  31.       {   
  32.   
  33.          DisplayRunningMessage();   
  34.   
  35.          DisplayDebugMessage();   
  36.   
  37.         
  38.   
  39.          MessageBox(0,"Hello","Message",0);   
  40.   
  41.         
  42.   
  43.          Console.ReadLine();   
  44.   
  45.       }   
  46.   
  47.         
  48.   
  49.       [Conditional("DEBUG")]   
  50.   
  51.       private static void DisplayRunningMessage()   
  52.   
  53.       {   
  54.   
  55.          Console.WriteLine("開始運行Main子程序。當前時間是"+DateTime.Now);   
  56.   
  57.       }   
  58.   
  59.      
  60.   
  61.       [Conditional("DEBUG")]   
  62.   
  63.       [Obsolete]   
  64.   
  65.       private static void DisplayDebugMessage()   
  66.   
  67.       {   
  68.   
  69.          Console.WriteLine("開始Main子程序");   
  70.   
  71.       }   
  72.   
  73.    }   
  74.   
  75. }    
#define DEBUG //這裏定義條件

    

using System;

using System.Runtime.InteropServices;

using System.Diagnostics;

    

namespace AttributeDemo

{

   class MainProgramClass

   {

 

      [DllImport("User32.dll")]

      public static extern int MessageBox(int hParent, string Message, string Caption, int Type);

     

      static void Main(string[] args)

      {

         DisplayRunningMessage();

         DisplayDebugMessage();

     

         MessageBox(0,"Hello","Message",0);

     

         Console.ReadLine();

      }

     

      [Conditional("DEBUG")]

      private static void DisplayRunningMessage()

      {

         Console.WriteLine("開始運行Main子程序。當前時間是"+DateTime.Now);

      }

  

      [Conditional("DEBUG")]

      [Obsolete]

      private static void DisplayDebugMessage()

      {

         Console.WriteLine("開始Main子程序");

      }

   }

}  

  

如果在一個程序元素前面聲明一個Attribute,那麼就表示這個Attribute被施加到該元素上,前面的代碼,[DllImport]施加到MessageBox函數上, [Conditional]施加到DisplayRuntimeMessage方法和DisplayDebugMessage方法,[Obsolete]施加到DisplayDebugMessage方法上。

根據上面涉及到的三個Attribute的說明,我們可以猜到程序運行的時候產生的輸出:DllImport Attribute表明了MessageBox是User32.DLL中的函數,這樣我們就可以像內部方法一樣調用這個函數。

重要的一點就是Attribute就是一個類,所以DllImport也是一個類,Attribute類是在編譯的時候被實例化的,而不是像通常的類那樣在運行時候才實例化。Attribute實例化的時候根據該Attribute類的設計可以帶參數,也可以不帶參數,比如DllImport就帶有"User32.dll"的參數。Conditional對滿足參數的定義條件的代碼進行編譯,如果沒有定義DEBUG,那麼該方法將不被編譯,讀者可以把#define DEBUG一行註釋掉看看輸出的結果(release版本,在Debug版本中Conditional的debug總是成立的)。Obsolete表明了DispalyDebugMessage方法已經過時了,它有一個更好的方法來代替它,當我們的程序調用一個聲明瞭Obsolete的方法時,那麼編譯器會給出信息,Obsolete還有其他兩個重載的版本。大家可以參考msdn中關於的ObsoleteAttribute 類的描述。

Attribute類

除了.NET提供的那些Attribute派生類之外,我們可以自定義我們自己的Attribute,所有自定義的Attribute必須從Attribute類派生。現在我們來看一下Attribute 類的細節:

protected Attribute(): 保護的構造器,只能被Attribute的派生類調用。

三個靜態方法:

static Attribute GetCustomAttribute():這個方法有8種重載的版本,它被用來取出施加在類成員上指定類型的Attribute。

static Attribute[] GetCustomAttributes(): 這個方法有16種重載版本,用來取出施加在類成員上指定類型的Attribute數組。

static bool IsDefined():由八種重載版本,看是否指定類型的定製attribute被施加到類的成員上面。

實例方法:

bool IsDefaultAttribute(): 如果Attribute的值是默認的值,那麼返回true。

bool Match():表明這個Attribute實例是否等於一個指定的對象。

公共屬性: TypeId: 得到一個唯一的標識,這個標識被用來區分同一個Attribute的不同實例。

我們簡單地介紹了Attribute類的方法和屬性,還有一些是從object繼承來的。這裏就不列出來了。

下面介紹如何自定義一個Attribute: 自定義一個Attribute並不需要特別的知識,其實就和編寫一個類差不多。自定義的Attribute必須直接或者間接地從Attribute這個類派生,如:

public MyCustomAttribute : Attribute { ... }

這裏需要指出的是Attribute的命名規範,也就是你的Attribute的類名+"Attribute",當你的Attribute施加到一個程序的元素上的時候,編譯器先查找你的Attribute的定義,如果沒有找到,那麼它就會查找“Attribute名稱"+Attribute的定義。如果都沒有找到,那麼編譯器就報錯。

對於一個自定義的Attribute,你可以通過AttributeUsage的Attribute來限定你的Attribute 所施加的元素的類型。代碼形式如下: [AttriubteUsage(參數設置)] public 自定義Attribute : Attribute { ... }

非常有意思的是,AttributeUsage本身也是一個Attribute,這是專門施加在Attribute類的Attribute. AttributeUsage自然也是從Attribute派生,它有一個帶參數的構造器,這個參數是AttributeTargets的枚舉類型。下面是AttributeTargets 的定義:

  1. public enum AttributeTargets   
  2.   
  3. {   
  4.   
  5.    All=16383,   
  6.   
  7.    Assembly=1,   
  8.   
  9.    Module=2,   
  10.   
  11.    Class=4,   
  12.   
  13.    Struct=8,   
  14.   
  15.    Enum=16,   
  16.   
  17.    Constructor=32,   
  18.   
  19.    Method=64,   
  20.   
  21.    Property=128,   
  22.   
  23.    Field=256,   
  24.   
  25.    Event=512,   
  26.   
  27.    Interface=1024,   
  28.   
  29.    Parameter=2048,   
  30.   
  31.    Delegate=4096,   
  32.   
  33.    ReturnValue=8192   
  34.   
  35. }     
public enum AttributeTargets

{

   All=16383,

   Assembly=1,

   Module=2,

   Class=4,

   Struct=8,

   Enum=16,

   Constructor=32,

   Method=64,

   Property=128,

   Field=256,

   Event=512,

   Interface=1024,

   Parameter=2048,

   Delegate=4096,

   ReturnValue=8192

}   

作爲參數的AttributeTarges的值允許通過“或”操作來進行多個值得組合,如果你沒有指定參數,那麼默認參數就是All 。 AttributeUsage除了繼承Attribute 的方法和屬性之外,還定義了以下三個屬性:

AllowMultiple: 讀取或者設置這個屬性,表示是否可以對一個程序元素施加多個Attribute 。

Inherited:讀取或者設置這個屬性,表示是否施加的Attribute 可以被派生類繼承或者重載。

ValidOn: 讀取或者設置這個屬性,指明Attribute 可以被施加的元素的類型。

AttributeUsage 的使用例子:

 

  1. using System;    
  2.   
  3. namespace AttTargsCS    
  4.   
  5. {    
  6.   
  7.   
  8.   
  9.    // 該Attribute只對類有效.    
  10.   
  11.    [AttributeUsage(AttributeTargets.Class)]   
  12.   
  13.    public class ClassTargetAttribute : Attribute    
  14.   
  15.    {    
  16.   
  17.     }    
  18.   
  19.   
  20.   
  21.   
  22.   
  23.    // 該Attribute只對方法有效.    
  24.   
  25.    [AttributeUsage(AttributeTargets.Method)]   
  26.   
  27.    public class MethodTargetAttribute : Attribute    
  28.   
  29.    {    
  30.   
  31.     }    
  32.   
  33.   
  34.   
  35.   
  36.   
  37.    // 該Attribute只對構造器有效。   
  38.   
  39.    [AttributeUsage(AttributeTargets.Constructor)]   
  40.   
  41.    public class ConstructorTargetAttribute : Attribute    
  42.   
  43.    {    
  44.   
  45.     }    
  46.   
  47.   
  48.   
  49.   
  50.   
  51.    // 該Attribute只對字段有效.    
  52.   
  53.    [AttributeUsage(AttributeTargets.Field)]   
  54.   
  55.    public class FieldTargetAttribute : Attribute   
  56.   
  57.    {   
  58.   
  59.    }    
  60.   
  61.   
  62.   
  63.       
  64.   
  65.   // 該Attribute對類或者方法有效(組合).    
  66.   
  67.   [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]   
  68.   
  69.    public class ClassMethodTargetAttribute : Attribute   
  70.   
  71.    {   
  72.   
  73.     }    
  74.   
  75.   
  76.   
  77.   
  78.   
  79.    // 該Attribute對所有的元素有效.   
  80.   
  81.    [AttributeUsage(AttributeTargets.All)]   
  82.   
  83.    public class AllTargetsAttribute : Attribute    
  84.   
  85.   {    
  86.   
  87.    }    
  88.   
  89.   
  90.   
  91.    //上面定義的Attribute施加到程序元素上的用法   
  92.   
  93.    [ClassTarget]  //施加到類   
  94.   
  95.    [ClassMethodTarget]//施加到類   
  96.   
  97.    [AllTargets] //施加到類   
  98.   
  99.    public class TestClassAttribute   
  100.   
  101.    {    
  102.   
  103.       [ConstructorTarget] //施加到構造器   
  104.   
  105.       [AllTargets] //施加到構造器   
  106.   
  107.       TestClassAttribute()   
  108.   
  109.       {    
  110.   
  111.        }    
  112.   
  113.   
  114.   
  115.       [MethodTarget] //施加到方法   
  116.   
  117.       [ClassMethodTarget] //施加到方法   
  118.   
  119.       [AllTargets] //施加到方法   
  120.   
  121.       public void Method1()   
  122.   
  123.       {   
  124.   
  125.       }   
  126.   
  127.         
  128.   
  129.       [FieldTarget] //施加到字段   
  130.   
  131.       [AllTargets] //施加到字段   
  132.   
  133.       public int myInt;    
  134.   
  135.   
  136.   
  137.       static void Main(string[] args)   
  138.   
  139.       {    
  140.   
  141.       }    
  142.   
  143.    }   
  144.   
  145. }  
using System; 

namespace AttTargsCS 

{ 



   // 該Attribute只對類有效. 

   [AttributeUsage(AttributeTargets.Class)]

   public class ClassTargetAttribute : Attribute 

   { 

    } 





   // 該Attribute只對方法有效. 

   [AttributeUsage(AttributeTargets.Method)]

   public class MethodTargetAttribute : Attribute 

   { 

    } 





   // 該Attribute只對構造器有效。

   [AttributeUsage(AttributeTargets.Constructor)]

   public class ConstructorTargetAttribute : Attribute 

   { 

    } 





   // 該Attribute只對字段有效. 

   [AttributeUsage(AttributeTargets.Field)]

   public class FieldTargetAttribute : Attribute

   {

   } 



   

  // 該Attribute對類或者方法有效(組合). 

  [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]

   public class ClassMethodTargetAttribute : Attribute

   {

    } 





   // 該Attribute對所有的元素有效.

   [AttributeUsage(AttributeTargets.All)]

   public class AllTargetsAttribute : Attribute 

  { 

   } 



   //上面定義的Attribute施加到程序元素上的用法

   [ClassTarget]  //施加到類

   [ClassMethodTarget]//施加到類

   [AllTargets] //施加到類

   public class TestClassAttribute

   { 

      [ConstructorTarget] //施加到構造器

      [AllTargets] //施加到構造器

      TestClassAttribute()

      { 

       } 



      [MethodTarget] //施加到方法

      [ClassMethodTarget] //施加到方法

      [AllTargets] //施加到方法

      public void Method1()

      {

      }

     

      [FieldTarget] //施加到字段

      [AllTargets] //施加到字段

      public int myInt; 



      static void Main(string[] args)

      { 

      } 

   }

}

至此,我們介紹了有關Attribute類和它們的代碼格式。你一定想知道到底如何在你的應用程序中使用Attribute,如果僅僅是前面介紹的內容,還是不足以說明Attribute有什麼實用價值的話,那麼從後面的章節開始我們將介紹幾個Attribute的不同用法,相信你一定會對Attribute有一個新的瞭解。(待續)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章