Attribute在.net編程中的應用(一)
【IT168 技術(shù)文檔】Attribute的基本概念
經(jīng)常有朋友問(wèn),Attribute是什么?它有什么用?好像沒(méi)有這個(gè)東東程序也能運行。實(shí)際上在.Net中,Attribute是一個(gè)非常重要的組成部分,為了幫助大家理解和掌握Attribute,以及它的使用方法,特地收集了幾個(gè)Attribute使用的例子,提供給大家參考。
在具體的演示之前,我想先大致介紹一下Attribute。我們知道在類(lèi)的成員中有property成員,二者在中文中都做屬性解釋?zhuān)敲此鼈兊降资遣皇峭粋€(gè)東西呢?從代碼上看,明顯不同,首先就是它們的在代碼中的位置不同,其次就是寫(xiě)法不同(Attribute必須寫(xiě)在一對方括符中)。
什么是Atrribute
首先,我們肯定Attribute是一個(gè)類(lèi),下面是msdn文檔對它的描述:
公共語(yǔ)言運行時(shí)允許你添加類(lèi)似關(guān)鍵字的描述聲明,叫做attributes, 它對程序中的元素進(jìn)行標注,如類(lèi)型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數據保存在一起,可以用來(lái)向運行時(shí)描述你的代碼,或者在程序運行的時(shí)候影響應用程序的行為。
在.NET中,Attribute被用來(lái)處理多種問(wèn)題,比如序列化、程序的安全特征、防止即時(shí)編譯器對程序代碼進(jìn)行優(yōu)化從而代碼容易調試等等。下面,我們先來(lái)看幾個(gè)在.NET中標準的屬性的使用,稍后我們再回過(guò)頭來(lái)討論Attribute這個(gè)類(lèi)本身。(文中的代碼使用C#編寫(xiě),但同樣適用所有基于.NET的所有語(yǔ)言)
Attribute作為編譯器的指令
在C#中存在著(zhù)一定數量的編譯器指令,如:#define DEBUG, #undefine DEBUG, #if等。這些指令專(zhuān)屬于C#,而且在數量上是固定的。而Attribute用作編譯器指令則不受數量限制。比如下面的三個(gè)Attribute:
Conditional:起條件編譯的作用,只有滿(mǎn)足條件,才允許編譯器對它的代碼進(jìn)行編譯。一般在程序調試的時(shí)候使用。 DllImport:用來(lái)標記非.NET的函數,表明該方法在一個(gè)外部的DLL中定義。 Obsolete:這個(gè)屬性用來(lái)標記當前的方法已經(jīng)被廢棄,不再使用了。
下面的代碼演示了上述三個(gè)屬性的使用:
#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("開(kāi)始運行Main子程序。當前時(shí)間是"+DateTime.Now);}[Conditional("DEBUG")][Obsolete]private static void DisplayDebugMessage(){Console.WriteLine("開(kāi)始Main子程序");}}}
如果在一個(gè)程序元素前面聲明一個(gè)Attribute,那么就表示這個(gè)Attribute被施加到該元素上,前面的代碼,[DllImport]施加到MessageBox函數上, [Conditional]施加到DisplayRuntimeMessage方法和DisplayDebugMessage方法,[Obsolete]施加到DisplayDebugMessage方法上。
根據上面涉及到的三個(gè)Attribute的說(shuō)明,我們可以猜到程序運行的時(shí)候產(chǎn)生的輸出:DllImport Attribute表明了MessageBox是User32.DLL中的函數,這樣我們就可以像內部方法一樣調用這個(gè)函數。
重要的一點(diǎn)就是Attribute就是一個(gè)類(lèi),所以DllImport也是一個(gè)類(lèi),Attribute類(lèi)是在編譯的時(shí)候被實(shí)例化的,而不是像通常的類(lèi)那樣在運行時(shí)候才實(shí)例化。Attribute實(shí)例化的時(shí)候根據該Attribute類(lèi)的設計可以帶參數,也可以不帶參數,比如DllImport就帶有"User32.dll"的參數。Conditional對滿(mǎn)足參數的定義條件的代碼進(jìn)行編譯,如果沒(méi)有定義DEBUG,那么該方法將不被編譯,讀者可以把#define DEBUG一行注釋掉看看輸出的結果(release版本,在Debug版本中Conditional的debug總是成立的)。Obsolete表明了DispalyDebugMessage方法已經(jīng)過(guò)時(shí)了,它有一個(gè)更好的方法來(lái)代替它,當我們的程序調用一個(gè)聲明了Obsolete的方法時(shí),那么編譯器會(huì )給出信息,Obsolete還有其他兩個(gè)重載的版本。大家可以參考msdn中關(guān)于的ObsoleteAttribute 類(lèi)的描述。
Attribute類(lèi)
除了.NET提供的那些Attribute派生類(lèi)之外,我們可以自定義我們自己的Attribute,所有自定義的Attribute必須從Attribute類(lèi)派生?,F在我們來(lái)看一下Attribute 類(lèi)的細節:
protected Attribute(): 保護的構造器,只能被Attribute的派生類(lèi)調用。
三個(gè)靜態(tài)方法:
static Attribute GetCustomAttribute():這個(gè)方法有8種重載的版本,它被用來(lái)取出施加在類(lèi)成員上指定類(lèi)型的Attribute。
static Attribute[] GetCustomAttributes(): 這個(gè)方法有16種重載版本,用來(lái)取出施加在類(lèi)成員上指定類(lèi)型的Attribute數組。
static bool IsDefined():由八種重載版本,看是否指定類(lèi)型的定制attribute被施加到類(lèi)的成員上面。
實(shí)例方法:
bool IsDefaultAttribute(): 如果Attribute的值是默認的值,那么返回true。
bool Match():表明這個(gè)Attribute實(shí)例是否等于一個(gè)指定的對象。
公共屬性: TypeId: 得到一個(gè)唯一的標識,這個(gè)標識被用來(lái)區分同一個(gè)Attribute的不同實(shí)例。
我們簡(jiǎn)單地介紹了Attribute類(lèi)的方法和屬性,還有一些是從object繼承來(lái)的。這里就不列出來(lái)了。
下面介紹如何自定義一個(gè)Attribute: 自定義一個(gè)Attribute并不需要特別的知識,其實(shí)就和編寫(xiě)一個(gè)類(lèi)差不多。自定義的Attribute必須直接或者間接地從Attribute這個(gè)類(lèi)派生,如:
public MyCustomAttribute : Attribute { ... }
這里需要指出的是Attribute的命名規范,也就是你的Attribute的類(lèi)名+"Attribute",當你的Attribute施加到一個(gè)程序的元素上的時(shí)候,編譯器先查找你的Attribute的定義,如果沒(méi)有找到,那么它就會(huì )查找“Attribute名稱(chēng)"+Attribute的定義。如果都沒(méi)有找到,那么編譯器就報錯。
對于一個(gè)自定義的Attribute,你可以通過(guò)AttributeUsage的Attribute來(lái)限定你的Attribute 所施加的元素的類(lèi)型。代碼形式如下: [AttriubteUsage(參數設置)] public 自定義Attribute : Attribute { ... }
非常有意思的是,AttributeUsage本身也是一個(gè)Attribute,這是專(zhuān)門(mén)施加在A(yíng)ttribute類(lèi)的Attribute. AttributeUsage自然也是從Attribute派生,它有一個(gè)帶參數的構造器,這個(gè)參數是AttributeTargets的枚舉類(lèi)型。下面是AttributeTargets 的定義:
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的值允許通過(guò)“或”操作來(lái)進(jìn)行多個(gè)值得組合,如果你沒(méi)有指定參數,那么默認參數就是All 。 AttributeUsage除了繼承Attribute 的方法和屬性之外,還定義了以下三個(gè)屬性:
AllowMultiple: 讀取或者設置這個(gè)屬性,表示是否可以對一個(gè)程序元素施加多個(gè)Attribute 。
Inherited:讀取或者設置這個(gè)屬性,表示是否施加的Attribute 可以被派生類(lèi)繼承或者重載。
ValidOn: 讀取或者設置這個(gè)屬性,指明Attribute 可以被施加的元素的類(lèi)型。