1.什么是Attribute?
特性(Attribute)是用於在運行時傳遞程序中各種元素(比如類、方法、結構、枚舉、組件等)的行為信息的聲明性標簽。您可以通過使用特性向程序添加聲明性信息。一個聲明性標簽是通過放置在它所應用的元素前面的方括號([ ])來描述的。
特性(Attribute)用於添加元數據,如編譯器指令和注釋、描述、方法、類等其他信息。.Net 框架提供了兩種類型的特性:預定義特性和自定義特性。
規定特性(Attribute)
規定特性(Attribute)的語法如下:
[attribute(positional_parameters, name_parameter = value, ...)]
element
特性(Attribute)的名稱和值是在方括號內規定的,放置在它所應用的元素之前。positional_parameters 規定必需的信息,name_parameter 規定可選的信息。
預定義特性(Attribute)
.Net 框架提供了三種預定義特性:
- AttributeUsage
- Conditional
- Obsolete
AttributeUsage
預定義特性 AttributeUsage 描述了如何使用一個自定義特性類。它規定了特性可應用到的項目的類型。
規定該特性的語法如下:
[AttributeUsage( validon, AllowMultiple=allowmultiple, Inherited=inherited )]
其中:
- 參數 validon 規定特性可被放置的語言元素。它是枚舉器 AttributeTargets 的值的組合。默認值是 AttributeTargets.All。
- 參數 allowmultiple(可選的)為該特性的 AllowMultiple 屬性(property)提供一個布爾值。如果為 true,則該特性是多用的。默認值是 false(單用的)。
- 參數 inherited(可選的)為該特性的 Inherited 屬性(property)提供一個布爾值。如果為 true,則該特性可被派生類繼承。默認值是 false(不被繼承)。
例如:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
Conditional
這個預定義特性標記了一個條件方法,其執行依賴於它頂的預處理標識符。
它會引起方法調用的條件編譯,取決於指定的值,比如 Debug 或 Trace。例如,當調試代碼時顯示變量的值。
規定該特性的語法如下:
[Conditional(conditionalSymbol)]
#define DEBUG using System; using System.Diagnostics; public class Myclass { [Conditional("DEBUG")] public static void Message(string msg) { Console.WriteLine(msg); } } class Test { static void function1() { Myclass.Message("In Function 1."); function2(); } static void function2() { Myclass.Message("In Function 2."); } public static void Main() { Myclass.Message("In Main function."); function1(); Console.ReadKey(); } }
當上面的代碼被編譯和執行時,它會產生下列結果:
In Main function In Function 1 In Function 2
Obsolete
這個預定義特性標記了不應被使用的程序實體。它可以讓您通知編譯器丟棄某個特定的目標元素。例如,當一個新方法被用在一個類中,但是您仍然想要保持類中的舊方法,您可以通過顯示一個應該使用新方法,而不是舊方法的消息,來把它標記為 obsolete(過時的)。
規定該特性的語法如下:
[Obsolete(message)]
[Obsolete(message, iserror)]
其中:
- 參數 message,是一個字符串,描述項目為什么過時的原因以及該替代使用什么。
- 參數 iserror,是一個布爾值。如果該值為 true,編譯器應把該項目的使用當作一個錯誤。默認值是 false(編譯器生成一個警告)。
下面的實例演示了該特性:
using System; public class MyClass { [Obsolete("Don't use OldMethod, use NewMethod instead", true)] static void OldMethod() { Console.WriteLine("It is the old method"); } static void NewMethod() { Console.WriteLine("It is the new method"); } public static void Main() { OldMethod(); } }
當您嘗試編譯該程序時,編譯器會給出一個錯誤消息說明:
Don't use OldMethod, use NewMethod instead
創建自定義特性(Attribute)
.Net 框架允許創建自定義特性,用於存儲聲明性的信息,且可在運行時被檢索。該信息根據設計標准和應用程序需要,可與任何目標元素相關。
創建並使用自定義特性包含四個步驟:
- 聲明自定義特性
- 構建自定義特性
- 在目標程序元素上應用自定義特性
- 通過反射訪問特性
最后一個步驟包含編寫一個簡單的程序來讀取元數據以便查找各種符號。元數據是用於描述其他數據的數據和信息。該程序應使用反射來在運行時訪問特性。我們將在下一章詳細討論這點。
聲明自定義特性
一個新的自定義特性應派生自 System.Attribute 類。例如:
// 一個自定義特性 BugFix 被賦給類及其成員 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class DeBugInfo : System.Attribute
在上面的代碼中,我們已經聲明了一個名為 DeBugInfo 的自定義特性。
構建自定義特性
讓我們構建一個名為 DeBugInfo 的自定義特性,該特性將存儲調試程序獲得的信息。它存儲下面的信息:
- bug 的代碼編號
- 辨認該 bug 的開發人員名字
- 最后一次審查該代碼的日期
- 一個存儲了開發人員標記的字符串消息
我們的 DeBugInfo 類將帶有三個用於存儲前三個信息的私有屬性(property)和一個用於存儲消息的公有屬性(property)。所以 bug 編號、開發人員名字和審查日期將是 DeBugInfo 類的必需的定位( positional)參數,消息將是一個可選的命名(named)參數。
每個特性必須至少有一個構造函數。必需的定位( positional)參數應通過構造函數傳遞。下面的代碼演示了 DeBugInfo 類:
// 一個自定義特性 BugFix 被賦給類及其成員 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class DeBugInfo : System.Attribute { private int bugNo; private string developer; private string lastReview; public string message; public DeBugInfo(int bg, string dev, string d) { this.bugNo = bg; this.developer = dev; this.lastReview = d; } public int BugNo { get { return bugNo; } } public string Developer { get { return developer; } } public string LastReview { get { return lastReview; } } public string Message { get { return message; } set { message = value; } } }
應用自定義特性
通過把特性放置在緊接着它的目標之前,來應用該特性:
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")] [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")] class Rectangle { // 成員變量 protected double length; protected double width; public Rectangle(double l, double w) { length = l; width = w; } [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")] public double GetArea() { return length * width; } [DeBugInfo(56, "Zara Ali", "19/10/2012")] public void Display() { Console.WriteLine("Length: {0}", length); Console.WriteLine("Width: {0}", width); Console.WriteLine("Area: {0}", GetArea()); } }
Attribute的目的是為元素提供關聯附加信息
實現自己的Attribute時需要注意的一些問題
1.自定義的Attribute必須直接或者間接繼承System.Attribute。
2.這里有一個約定:所有自定義的特性名稱都應該有個Attribute后綴。因為當你的Attribute施加到一個程序的元素上的時候,編譯器先查找你的Attribute的定義,如果沒有找到,那么它就會查找“Attribute名稱"+Attribute的定義。如果都沒有找到,那么編譯器就報錯。
下面是一些開發自定義Attribute時,可能需要用到的資料:
【1】Attribute可以關聯的元素包括:
程序集(assembly)、模塊(module)、類型(type)、屬性(property)、事件(event)、字段(field)、方法(method)、參數(param)、返回值(return)。
【2】AttributeTargets目標包括
標記 | 說明 |
All | 可以對任何應用程序元素應用屬性。 |
Assembly | 可以對程序集應用屬性。 |
Class | 可以對類應用屬性。 |
Constructor | 可以對構造函數應用屬性。 |
Delegate | 可以對委托應用屬性。 |
Enum | 可以對枚舉應用屬性。 |
Event | 可以對事件應用屬性。 |
Field | 可以對字段應用屬性。 |
GenericParameter | 可以對泛型參數應用屬性。 |
Interface | 可以對接口應用屬性。 |
Method | 可以對方法應用屬性。 |
Module | Module 指的是可移植的可執行文件(.dll 或 .exe),而非 Visual Basic 標准模塊。 |
Parameter | 可以對參數應用屬性。 |
Property | 可以對屬性 (Property) 應用屬性 (Attribute)。 |
ReturnValue | 可以對返回值應用屬性。 |
Struct | 可以對結構應用屬性,即值類型。 |
【3】AttributeUsageAttribute中的3個屬性(Property)說明:
屬性名 | 說明 |
ValidOn | 該定位參數指定可在其上放置所指示的屬性 (Attribute) 的程序元素。AttributeTargets 枚舉數中列出了可在其上放置屬性 (Attribute) 的所有可能元素的集合。可通過按位“或”運算組合多個 AttributeTargets 值,以獲取所需的有效程序元素組合。 |
AllowMultiple | 該命名參數指定能否為給定的程序元素多次指定所指示的屬性。 |
Inherited | 該命名參數指定所指示的屬性能否由派生類和重寫成員繼承。 |