1、引言
attribute是.NET架構引入的有一技術亮點,是以我們有必要花點時間來了解本文的内容,走進一個發現attribute登堂入室的入口。 因為.NET Framework中使用了大量的定制特性來完成代碼約定,[Serializable]、[Flags]、[DllImport]、 [AttributeUsage]這些的構造,相信我們都見過吧!那麼你是否了解其背後的技術。
提起特性,由于進階語言發展的曆史原因,不免讓人想起另一個耳熟能詳的名字:屬性。特性和屬性,往往給初學者或者從C++轉移到C#的人混淆的概念 沖擊。那麼,什麼是屬性,什麼是特性,二者的概念和差別,用法與示例,将在本文做以概括性的總結和比較,希望給你的了解帶來收獲。另外本文的主題以特性的 介紹為主,屬性的論述重點突出在二者的比較上,關于屬性的更多論述将在另一篇主題中詳細讨論,敬請關注。
2、概念引入
2.1、什麼是特性?
MADN的定義為:公共語言運作時允許添加類似關鍵字的描述聲明,叫做attributes, 它對程式中的元素進行标注,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework檔案的中繼資料儲存在一起,可以用來向運作時描述你的代碼,或者在程式運作的時候影響應用程式的行為。
我們簡單的總結為:定制特性attribute,本質上是一個類,其為目标元素提供關聯附加資訊,并在運作期以反射的方式來擷取附加資訊。具體的特性實作方法,在接下來的讨論中繼續深入。
2.2、什麼是屬性?
屬性是面向對象程式設計的基本概念,提供了對私有字段的通路封裝,在C#中以get和set通路器方法實作對可讀可寫屬性的操作,提供了安全和靈活的資料通路封裝。關于屬性的概念,不是本文的重點,而且相信大部分的技術人員應該對屬性有清晰的概念。以下是簡單的屬性示例:
2.3、差別與比較
通過對概念的澄清和曆史的回溯,我們知道特性和屬性隻是在名稱上有過糾葛,在MSDN上關于attribute的中文解釋甚至還是屬性,但是我同意 更通常的稱呼:特性。在功能上和應用上,二者其實沒有太多模糊的概念交叉,是以也沒有必要來比較其應用的異同點。本文則以特性的概念為重點,來讨論其應用 的場合和規則。
我了解的定制特性,就是為目标元素,可以是資料集、子產品、類、屬性、方法、甚至函數參數等加入附加資訊,類似于注釋,但是可以在運作期以反射的方式獲得。定制特性主要應用在序列化、編譯器指令、設計模式等方面。
3、通用規則
(1)定制特性可以應用的目标元素可以為:程式集(assembly)、子產品(module)、類型(type)、屬性(property)、事件(event)、字段(field)、方法(method)、參數(param)、傳回值(return),應該全了。
(2) 定制特性以[,]形式展現,放在緊挨着的元素上,多個特性可以應用于同一進制素,特性間以逗号隔開,以下表達規則有效:[AttributeUsage][ Flags]、[AttributeUsage, Flags]、[Flags, AttibuteUsageAttribute]、[AttributeUsage(), FlagesAttribute()]。
(3)attibute執行個體,是在編譯期進行初始化,而不是運作期。
(4)C#允許以指定的字首來表示特性所應用的目标元素,建議這樣來處理,因為顯式處理可以消除可能帶來的二義性。例如:
|
(5)定制特性類型,必須直接或者間接的繼承自System.Attribute類,而且該類型必須有公有構造函數來建立其執行個體。
(6)所有自定義的特性名稱都應該有個Attribute字尾,這是習慣性約定。
(7)定制特性也可以應用在其他定制特性上,這點也很好了解,因為定制特性本身也是一個類,遵守類的公有規則。例如很多時候我們的自定義定制特性會應用AttributeUsageAttribute特性,來控制如何應用新定義的特性。
|
(8)定制特性不會影響應用元素的任何功能,隻是約定了該元素具有的特質。
(9)所有非抽象特性必須具有public通路限制。
(10)特性常用于編譯器指令,突破#define,#undefine,#if,#endif的限制,而且更加靈活。
(11)定制特性常用于在運作期獲得代碼注釋資訊,以附加資訊來優化調試。
(12)定制特性可以應用在某些設計模式中,如工廠模式。
(13)定制特性還常用于位标記,非托管函數标記、方法廢棄标記等其他方面。
4、特性的應用
4.1、常用特性
常用特性,也就是.NET已經提供的固有特性,事實上在.NET架構中已經提供了豐富的固有特性由我們發揮,以下精選出我認為最常用、最典型的固有 特性做以簡單讨論,當然這隻是我的一家之言,亦不足道。我想了解特性,還是從這裡做為起點,從.NET提供的經典開始,或許是一種求知的捷徑,希望能給大 家以啟示。
1、AttributeUsage
AttributeUsage特性用于控制如何應用自定義特性到目标元素。關于AttributeTargets、AllowMultiple、 Inherited、ValidOn,請參閱示例說明和其他文檔。我們已經做了相當的介紹和示例說明,我們還是在實踐中自己體會更多吧!
2、Flags
以Flags特性來将枚舉數值看作位标記,而非單獨的數值,例如:
|
是以,以下實作就相當輕松,
|
請猜測結果是什麼,答案是:“Dog, Cat”。如果沒有Flags特别,這裡的結果将是“3”。關于位标記,也将在本系列的後續章回中有所交代,在此隻做以探讨止步。
3、DllImport
DllImport特性,可以讓我們調用非托管代碼,是以我們可以使用DllImport特性引入對Win32 API函數的調用,對于習慣了非托管代碼的程式員來說,這一特性無疑是救命的稻草。
|
4、Serializable
Serializable特性表明了應用的元素可以被序列化(serializated),序列化和反序列化是另一個可以深入讨論的話題,在此我們隻是提出概念,深入的研究有待以專門的主題來呈現,限于篇幅,此不贅述。
5、Conditional
Conditional特性,用于條件編譯,在調試時使用。注意:Conditional不可應用于資料成員和屬性。
還有其他的重要特性,包括:Description、DefaultValue、Category、ReadOnly、BrowerAble等,有時間可以深入研究。
4.2、自定義特性
既然attribute,本質上就是一個類,那麼我們就可以自定義更特定的attribute來滿足個性化要求,隻要遵守上述的12條規則,實作一個自定義特性其實是很容易的,典型的實作方法為:
1、定義特性
|
2、應用目标元素
|
3、擷取元素附加資訊
如果沒有什麼機制來在運作期來擷取Attribute的附加資訊,那麼attribute就沒有什麼存在的意義。是以,.NET中以反射機制來實作在運作期擷取attribute資訊,實作方法如下:
|
5、經典示例
5.1、小菜一碟
啥也不說了,看注釋吧!
|
啥也别想了,自己做一下試試。
5.2、他山之石
MSDN認為,特性 (Attribute) 描述如何将資料序列化,指定用于強制安全性的特性,并限制實時 (JIT) 編譯器的優化,進而使代碼易于調試。屬性 (Attribute) 還可以記錄檔案名或代碼作者,或在窗體開發階段控制控件和成員的可見性。
6、結論
Attribute是.NET引入的一大特色技術,但讨論的不是很多,是以拿出自己的體會來分享,希望就這一技術要點進行一番登堂入室的引導。更深 層次的應用,例如序列化、程式安全性、設計模式多方面都可以挖掘出閃耀的金子,這就是.NET在技術領域帶來的百變魅力吧!希望大家暢所欲言,來完善和補 充作者在這方面的不全面和認知上的不深入,那将是作者最大的鼓勵和動力。