撰寫自訂屬性
若要設計您自己的自訂屬性,您不需精通許多新概念。 如果您熟悉物件導向程式設計並知道如何設計類別,您已經具備大部分所需的知識。 自訂屬性基本上是直接或間接衍生自 System.Attribute 的傳統類別。 就像傳統的類別,自訂屬性包含儲存和擷取資料的方法。
正確設計自訂屬性類別的主要步驟如下:
套用 AttributeUsageAttribute
宣告屬性類別
宣告建構函式
宣告屬性
這個章節描述這些各個步驟並以自訂屬性範例作結束。
套用 AttributeUsageAttribute
自訂屬性宣告以 AttributeUsageAttribute 開頭,來定義您屬性類別的某些關鍵特性。 例如,您可以指定是否您的屬性可以被其他類別繼承,或指定屬性可以套用到哪些項目。 下列程式碼片段示範如何使用 AttributeUsageAttribute。
<AttributeUsage(AttributeTargets.All, Inherited := False, AllowMultiple := True)>
Public Class SomeClass
Inherits Attribute
'...
End Class
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[AttributeUsage(AttributeTargets::All, Inherited = false, AllowMultiple = true)]
System.AttributeUsageAttribute 有三個成員,對於建立自訂屬性非常重要:AttributeTargets、Inherited 及 AllowMultiple。
AttributeTargets 成員
前面範例中指定了 AttributeTargets.All,指示這個屬性可以套用到所有程式項目。 或者,您可以指定 AttributeTargets.Class,表示您的屬性只能套用至類別,或是指定 AttributeTargets.Method,表示您的屬性只能套用至方法。 所有程式項目都可以用這個方式使用自訂屬性來標示為描述。
您也可以傳遞多個 AttributeTargets 的執行個體。 下列程式碼片段指定自訂屬性可以套用至任何類別或方法。
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
Inherits Attribute
'...
End Class
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]
Inherited 屬性
Inherited 屬性指示您的屬性是否可以被類別 (衍生自套用您屬性的類別) 所繼承。 這個屬性接受 true (預設值) 或 false 旗標。 例如,下列程式碼範例中,MyAttribute 有預設值為 true 的 Inherited 值,而 YourAttribute 則有為 false 的 Inherited 值。
' This defaults to Inherited = true.
Public Class MyAttribute
Inherits Attribute
'...
End Class
<AttributeUsage(AttributeTargets.Method, Inherited := False)>
Public Class YourAttribute
Inherits Attribute
'...
End Class
// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
//...
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
//...
}
// This defaults to Inherited = true.
public ref class MyAttribute : Attribute
{
//...
};
[AttributeUsage(AttributeTargets::Method, Inherited = false)]
public ref class YourAttribute : Attribute
{
//...
};
接著套用兩個屬性至基底類別 MyClass 中的方法。
Public Class MeClass
<MyAttribute>
<YourAttribute>
Public Overridable Sub MyMethod()
'...
End Sub
End Class
public class MyClass
{
[MyAttribute]
[YourAttribute]
public virtual void MyMethod()
{
//...
}
}
public ref class MyClass
{
public:
[MyAttribute]
[YourAttribute]
virtual void MyMethod()
{
//...
}
};
最後,類別 YourClass 繼承自基底類別 MyClass。 方法 MyMethod 會顯示 MyAttribute,但不顯示 YourAttribute。
Public Class YourClass
Inherits MeClass
' MyMethod will have MyAttribute but not YourAttribute.
Public Overrides Sub MyMethod()
'...
End Sub
End Class
public class YourClass : MyClass
{
// MyMethod will have MyAttribute but not YourAttribute.
public override void MyMethod()
{
//...
}
}
public ref class YourClass : MyClass
{
public:
// MyMethod will have MyAttribute but not YourAttribute.
virtual void MyMethod() override
{
//...
}
};
AllowMultiple 屬性
AllowMultiple 屬性指示您屬性的多個執行個體是否可以在項目上存在。 如果設定成 true,允許多個執行個體存在;如果設定為 false (預設值),則只允許有一個執行個體。
下列程式碼範例中,MyAttribute 有預設為 false 的 AllowMultiple 值,而 YourAttribute 有 true 值。
' This defaults to AllowMultiple = false.
Public Class MyAttribute
Inherits Attribute
End Class
<AttributeUsage(AttributeTargets.Method, AllowMultiple := true)>
Public Class YourAttribute
Inherits Attribute
End Class
//This defaults to AllowMultiple = false.
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
//This defaults to AllowMultiple = false.
public ref class MyAttribute : Attribute
{
};
[AttributeUsage(AttributeTargets::Method, AllowMultiple = true)]
public ref class YourAttribute : Attribute
{
};
套用這些屬性的多個執行個體時,MyAttribute 產生編譯器錯誤。 下列程式碼範例示範 YourAttribute 的有效用法和 MyAttribute 的無效用法。
Public Class MyClass
' This produces an error.
' Duplicates are not allowed.
<MyAttribute>
<MyAttribute>
Public Sub MyMethod()
'...
End Sub
' This is valid.
<YourAttribute>
<YourAttribute>
Public Sub YourMethod()
'...
End Sub
End Class
public class MyClass
{
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
public void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
public void YourMethod()
{
//...
}
}
public ref class MyClass
{
public:
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
void YourMethod()
{
//...
}
};
如果 AllowMultiple 屬性和 Inherited 屬性都設成 true,繼承另一個類別的類別可以繼承屬性,並且使得相同屬性的執行個體套用於相同子類別中。 如果 AllowMultiple 設定為 false,父類別中的任何屬性值將被子類別中相同屬性的任何新執行個體覆寫。
宣告屬性類別
套用 AttributeUsageAttribute 之後,就可以開始定義屬性的細節。 屬性類別的宣告看起來類似傳統類別的宣告,如下列程式碼所示範。
<AttributeUsage(AttributeTargets.Method)>
Public Class MyAttribute
Inherits Attribute
' . . .
End Class
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
// . . .
}
[AttributeUsage(AttributeTargets::Method)]
public ref class MyAttribute : Attribute
{
// . . .
};
這個屬性的定義顯示下列要點:
屬性類別必須宣告為公用 (Public) 類別。
根據慣例,屬性類別的名稱以 Attribute 做為結尾。 即使沒有必要,仍建議使用此慣例以提高可讀性。 套用屬性時,文字結尾的 Attribute 是選擇性的。
所有屬性類別必須直接或間接繼承自 System.Attribute。
在 Microsoft Visual Basic 中,所有自訂屬性類別都必須具有 AttributeUsageAttribute 屬性。
宣告建構函式
屬性以傳統類別的相同方式使用建構函式來初始化。 下列程式碼片段說明一般屬性建構函式。 這個公用建構函式具有一個參數並設定它的值等於成員變數。
Public Sub New(myvalue As Boolean)
Me.myvalue = myvalue
End Sub
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
MyAttribute(bool myvalue)
{
this->myvalue = myvalue;
}
您可以多載建構函式以容納不同組合的值。 如果您也定義您自訂屬性類別的屬性,您可以在初始化屬性時,使用指名和位置參數的組合。 基本上,您定義所有必要參數為位置參數,和所有選擇性參數為具名參數。 在這個狀況中,不能不使用必要參數來初始化屬性。 所有其他屬性為選擇性的。 請注意,在 Visual Basic 中,屬性類別的建構函式不能使用 ParamArray 引數。
下列程式碼範例示範如何使用選擇性和必要參數,來套用使用先前建構函式的屬性。 它假設屬性有一個必要的布林 (Boolean) 值和一個選擇性字串屬性。
' One required (positional) and one optional (named) parameter are applied.
<MyAttribute(false, OptionalParameter := "optional data")>
Public Class SomeClass
'...
End Class
' One required (positional) parameter is applied.
<MyAttribute(false)>
Public Class SomeOtherClass
'...
End Class
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public class SomeClass
{
//...
}
// One required (positional) parameter is applied.
[MyAttribute(false)]
public class SomeOtherClass
{
//...
}
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public ref class SomeClass
{
//...
};
// One required (positional) parameter is applied.
[MyAttribute(false)]
public ref class SomeOtherClass
{
//...
};
宣告屬性
如果您想要定義具名參數,或是提供容易的方式來傳回屬性所儲存的值,請宣告屬性。 屬性 (Attribute) 的屬性 (Property) 應該以將要傳回的資料型別描述宣告為公用實體 (Entity)。 定義保留您屬性值的變數並將它與 get 和 set 方法關聯。 下列程式碼範例示範如何在您的屬性中實作簡單屬性。
Public Property MyProperty As Boolean
Get
Return Me.myvalue
End Get
Set
Me.myvalue = Value
End Set
End Property
public bool MyProperty
{
get {return this.myvalue;}
set {this.myvalue = value;}
}
property bool MyProperty
{
bool get() {return this->myvalue;}
void set(bool value) {this->myvalue = value;}
}
自訂屬性範例
這個章節結合前面資訊,並示範如何設計簡單屬性以記錄有關一段程式碼作者的資訊。 這個範例中的屬性儲存程式設計人員的名稱和等級,以及是否已經檢閱程式碼。 它使用三個私用 (Private) 變數來存放要儲存的實際值。 每一個變數由取得和設定數值的公用屬性來代表。 最後,以兩個必要參數定義建構函式。
<AttributeUsage(AttributeTargets.All)>
Public Class DeveloperAttribute
Inherits Attribute
' Private fields.
Private myname As String
Private mylevel As String
Private myreviewed As Boolean
' This constructor defines two required parameters: name and level.
Public Sub New(name As String, level As String)
Me.myname = name
Me.mylevel = level
Me.myreviewed = False
End Sub
' Define Name property.
' This is a read-only attribute.
Public Overridable ReadOnly Property Name() As String
Get
Return myname
End Get
End Property
' Define Level property.
' This is a read-only attribute.
Public Overridable ReadOnly Property Level() As String
Get
Return mylevel
End Get
End Property
' Define Reviewed property.
' This is a read/write attribute.
Public Overridable Property Reviewed() As Boolean
Get
Return myreviewed
End Get
Set
myreviewed = value
End Set
End Property
End Class
[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : 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;}
}
}
[AttributeUsage(AttributeTargets::All)]
public ref class DeveloperAttribute : Attribute
{
// Private fields.
private:
String^ name;
String^ level;
bool reviewed;
public:
// This constructor defines two required parameters: name and level.
DeveloperAttribute(String^ name, String^ level)
{
this->name = name;
this->level = level;
this->reviewed = false;
}
// Define Name property.
// This is a read-only attribute.
virtual property String^ Name
{
String^ get() {return name;}
}
// Define Level property.
// This is a read-only attribute.
virtual property String^ Level
{
String^ get() {return level;}
}
// Define Reviewed property.
// This is a read/write attribute.
virtual property bool Reviewed
{
bool get() {return reviewed;}
void set(bool value) {reviewed = value;}
}
};
您可以使用完整名稱 DeveloperAttribute,或使用縮寫名稱 Developer,以下列其中一種方式來套用這個屬性。
<Developer("Joan Smith", "1")>
-or-
<Developer("Joan Smith", "1", Reviewed := true)>
[Developer("Joan Smith", "1")]
-or-
[Developer("Joan Smith", "1", Reviewed = true)]
[Developer("Joan Smith", "1")]
-or-
[Developer("Joan Smith", "1", Reviewed = true)]
第一個範例示範只以必要指名參數套用的屬性,而第二範例則示範以必要和選擇性參數兩者都套用的屬性。