- 摘要:本文介紹C#編寫自訂特性(Attribute),自訂屬性本質上是直接或間接地從 System.Attribute 派生的傳統類。與傳統類一樣,自訂屬性也包含儲存和檢索資料的方法。
要設計自己的自訂屬性,不必掌握許多新的概念。如果熟悉物件導向的編程,並且知道如何設計類,就已具備了所需的大部分知識。自訂屬性本質上是直接或間接地從 System.Attribute 派生的傳統類。與傳統類一樣,自訂屬性也包含儲存和檢索資料的方法。
正確設計自訂屬性類的主要步驟如下:
本節描述上述每個步驟,並以自訂屬性樣本結束。
應用 AttributeUsageAttribute
自訂屬性聲明以 AttributeUsageAttribute 開始,而該屬性定義屬性類的一些主要屬性。例如,可指定屬性是否可被其他類繼承,或指定屬性可應用到哪些元素。下列程式碼片段說明了如何使用 AttributeUsageAttribute。
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
System.AttributeUsageAttribute 類包含三個對自訂屬性的建立具有重要意義的成員:AttributeTargets、Inherited 和 AllowMultiple。
AttributeTargets 成員
在前面的樣本中指定了 AttributeTargets.All,指示該屬性可以應用到所有程式元素。還可以指定 AttributeTargets.Class,指示屬性只可以應用於某個類;或指定 AttributeTargets.Method,指示屬性只可以應用於某個方法。所有程式元素都可通過這種方式由自訂屬性標記,以便對其進行描述。
還可傳遞 AttributeTargets 的多個執行個體。下列程式碼片段指定自訂屬性可應用到任何類或方法。
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
繼承屬性
Inherited 屬性指示屬性是否可由從該屬性應用到的類派生的類繼承。該屬性採用 true(預設值)或 false 標誌。例如,在下面的程式碼範例中,MyAttribute 的預設 Inherited 值為 true,而 YourAttribute 的 Inherited 值為 false。
//This defaults to Inherited = true.
public class MyAttribute :Attribute
{
}
[AttributeUsage( Inherited = false)]
public class YourAttribute : Attribute
{
}
然後,這兩個屬性應用到基類 MyClass 中的某個方法。
public class MyClass
{
[MyAttribute]
[YourAttribute]
public virtual void MyMethod()
{
//...
}
}
最後,YourClass 類從基類 MyClass 繼承。方法 MyMethod 顯示 MyAttribute,而不是 YourAttribute。
public class YourClass: MyClass
{
//MyMethod will have MyAttribute but not YourAttribute.
public override void MyMethod()
{
//...
}
}
AllowMultiple 屬性
AllowMultiple 屬性指示元素中是否可存在屬性的多個執行個體。如果設定為 true,則允許存在多個執行個體;如果設定為 false(預設值),則只允許存在一個執行個體。
在下面的程式碼範例中,MyAttribute 的預設 AllowMultiple 值為 false,而 YourAttribute 的對應值為 true。
//This defaults to AllowMultiple = false.
public class MyAttribute :Attribute
{
}
[AttributeUsage(AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
當應用這些屬性的多個執行個體時,MyAttribute 將產生編譯器錯誤。下面的程式碼範例顯示 YourAttribute 的有效用法和 MyAttribute 的無效用法。
public class MyClass
{
//This produces an error.
//Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
public void MyMethod() {
//...
}
//This is valid.
[YourAttribute]
[YourAttribute]
public void YourMethod(){
//...
}
}
如果 AllowMultiple 屬性和 Inherited 屬性都設定為 true,則從另一個類繼承的類可以繼承一個屬性,並在同一子類中應用同一屬性的另一個執行個體。如果 AllowMultiple 設定為 false,則父類中的所有屬性值將被子類中同一屬性的新執行個體重寫。
聲明屬性類
應用了 AttributeUsageAttribute 後,可以開始定義屬性細節。屬性類的聲明與傳統類的聲明類似,如下列代碼所示:
public class MyAttribute : System.Attribute
{
// . . .
}
此屬性定義說明了下列幾點:
屬性類必須聲明為公用類。
按照約定,屬性類的名稱以單詞 Attribute 結尾。雖然並不要求這樣,但出於可讀性目的,建議採用此約定。應用屬性時,可以選擇是否包含 Attribute 一詞。
所有屬性類都必須直接或間接地從 System.Attribute 繼承。
在 Microsoft Visual Basic 中,所有自訂屬性類都必須具有 AttributeUsageAttribute 屬性。
聲明建構函式
用建構函式初始化屬性的方法與對待傳統類的方法相同。下列程式碼片段闡釋了典型的屬性建構函式。該公用建構函式採用一個參數,並將其值設定為與成員變數相等。
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
可重載該建構函式以適應值的不同組合。如果同時為自訂屬性類定義了屬性,則在初始化屬性時可使用具名引數和定位參數的組合。通常情況下,將所有必選參數定義為定位參數,將所有選擇性參數定義為具名引數。在這種情況下,如果沒有必選參數,則無法初始化屬性。其他所有參數都是選擇性參數。請注意,在 Visual Basic 中,屬性類的建構函式不應使用 ParamArray 參數。
下面的程式碼範例顯示如何使用選擇性參數和必選參數應用使用上例中的建構函式的屬性。它假定該屬性有一個必選布爾值和一個可選字串屬性。
//One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
//One required (positional) parameter is applied.
[MyAttribute(false)]
聲明屬性
如果需要定義具名引數,或者要提供一種容易的方法來返回由屬性儲存區的值,請聲明屬性。應將屬性屬性聲明為帶有要返回的資料類型說明的公用實體。定義將儲存屬性值的變數,並將該變數與 get 方法和 set 方法關聯。下面的程式碼範例說明如何在屬性中實現一個簡單的屬性。
public bool MyProperty
{
get {return this.myvalue;}
set {this.myvalue = value;}
}
自訂屬性樣本
本節具體表現前面的資訊,並顯示如何設計一個簡單的屬性來記錄有關程式碼片段作者的資訊。該樣本中的屬性儲存區程式員的名字和層級,和關於該代碼是否已被複查過的資訊。該樣本使用三個私人變數儲存要儲存的實際值。每個變數用擷取和設定這些值的公用屬性工作表示。最後,用兩個必選參數定義建構函式。
[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : System.Attribute
{
//Private fields.
private string name;
private string level;
private bool reviewed;
//This constructor defines two required parameters: name and level.
public DeveloperAttribute(string name,string level)
{
this.name = name;
this.level = level;
this.reviewed = false;
}
//Define Name property.
//This is a read-only attribute.
public virtual string Name
{
get {return name;}
}
//Define Level property.
//This is a read-only attribute.
public virtual string Level
{
get {return level;}
}
//Define Reviewed property.
//This is a read/write attribute.
public virtual bool Reviewed
{
get {return reviewed;}
set {reviewed = value;}
}
}
可通過下列方法之一,使用全名 DeveloperAttribute 或使用縮寫名 Developer 來應用該屬性。
[Developer("Joan Smith", "1")]
[Developer("Joan Smith", "1", Reviewed = true)]
第一個樣本顯示只用必選具名引數應用的屬性,而第二個樣本顯示同時使用必選參數和選擇性參數應用的屬性。