寫入自訂屬性
若要設計自訂屬性,您並不需要了解很多新概念。 假如您擅長物件導向的程式設計,且了解如何設計類別,那麼您就已經擁有大部分所需的知識。 自訂屬性是一種直接或間接衍生自 System.Attribute 的傳統類別。 自訂屬性就像傳統類別一樣,含有儲存和擷取資料的方法。
正確設計自訂屬性的主要步驟如下:
本節會一一說明每個步驟,並於結尾提供 自訂屬性範例。
套用 AttributeUsageAttribute
自訂屬性宣告的開頭為 System.AttributeUsageAttribute 屬性,其會定義您屬性類別的一些主要特性。 例如,您可以指定屬性是否可由其他類別繼承屬性可以套用至哪一個項目。 下列程式碼片段示範如何使用 AttributeUsageAttribute:
[AttributeUsage(AttributeTargets::All, Inherited = false, AllowMultiple = true)]
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
<AttributeUsage(AttributeTargets.All, Inherited:=False, AllowMultiple:=True)>
Public Class SomeClass
Inherits Attribute
'...
End Class
AttributeUsageAttribute 有三個建立自訂屬性所需的重要成員:AttributeTargets、Inherited 及 AllowMultiple。
AttributeTargets 成員
在上述範例中,指定了 AttributeTargets.All,指出此屬性可以套用到所有程式元素。 或者,您也可以指定 AttributeTargets.Class,指出您的屬性可以套用到類別,或指定 AttributeTargets.Method,指出屬性只能套用至方法。 所有的程式項目都可以用這種方式透過自訂屬性標示為描述。
您也可以傳遞多個 AttributeTargets 值。 下列程式碼片段指定自訂屬性可以套用至任何類別或方法:
[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
Inherits Attribute
'...
End Class
Inherited 屬性
AttributeUsageAttribute.Inherited 屬性會指出,衍生自套用您屬性之類別的類別,是否可繼承您的屬性。 此屬性會接受 true
(預設值) 或 false
旗標。 在下列範例中,MyAttribute
的預設 Inherited 值為 true
,而 YourAttribute
的 Inherited 值為 false
:
// This defaults to Inherited = true.
public ref class MyAttribute : Attribute
{
//...
};
[AttributeUsage(AttributeTargets::Method, Inherited = false)]
public ref class YourAttribute : Attribute
{
//...
};
// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
//...
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
//...
}
' This defaults to Inherited = true.
Public Class MyAttribute
Inherits Attribute
'...
End Class
<AttributeUsage(AttributeTargets.Method, Inherited:=False)>
Public Class YourAttribute
Inherits Attribute
'...
End Class
兩個屬性接著會套用到基底類別 MyClass
中的方法:
public ref class MyClass
{
public:
[MyAttribute]
[YourAttribute]
virtual void MyMethod()
{
//...
}
};
public class MyClass
{
[MyAttribute]
[YourAttribute]
public virtual void MyMethod()
{
//...
}
}
Public Class MeClass
<MyAttribute>
<YourAttribute>
Public Overridable Sub MyMethod()
'...
End Sub
End Class
最後,會從基底類別 YourClass
繼承類別 MyClass
。 此方法 MyMethod
顯示 MyAttribute
,但不是 YourAttribute
:
public ref class YourClass : MyClass
{
public:
// MyMethod will have MyAttribute but not YourAttribute.
virtual void MyMethod() override
{
//...
}
};
public class YourClass : MyClass
{
// MyMethod will have MyAttribute but not YourAttribute.
public override void MyMethod()
{
//...
}
}
Public Class YourClass
Inherits MeClass
' MyMethod will have MyAttribute but not YourAttribute.
Public Overrides Sub MyMethod()
'...
End Sub
End Class
AllowMultiple 屬性
AttributeUsageAttribute.AllowMultiple 屬性會指出項目上是否可以有您屬性的多個執行個體。 如果設定為 true
,則會允許多個執行個體。 如果設定為 false
(預設值),則只允許一個執行個體。
在下列範例中,MyAttribute
有預設的 AllowMultiple 值 false
,而 YourAttribute
有 true
的值:
//This defaults to AllowMultiple = false.
public ref class MyAttribute : Attribute
{
};
[AttributeUsage(AttributeTargets::Method, AllowMultiple = true)]
public ref class YourAttribute : Attribute
{
};
//This defaults to AllowMultiple = false.
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
' This defaults to AllowMultiple = false.
Public Class MyAttribute
Inherits Attribute
End Class
<AttributeUsage(AttributeTargets.Method, AllowMultiple:=true)>
Public Class YourAttribute
Inherits Attribute
End Class
當套用這些屬性的多個執行個體時,MyAttribute
會產生編譯器錯誤。 下列程式碼範例示範有效的 YourAttribute
用法和無效的 MyAttribute
用法:
public ref class MyClass
{
public:
// This produces an error.
// Duplicates are not allowed.
[MyAttribute]
[MyAttribute]
void MyMethod()
{
//...
}
// This is valid.
[YourAttribute]
[YourAttribute]
void YourMethod()
{
//...
}
};
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 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
如果 AllowMultiple 屬性和 Inherited 屬性都設定為 true
,繼承自另一個類別的類別可以繼承屬性,並在同一個子類別中套用同一屬性的另一個執行個體。 如果 AllowMultiple 設定為 false
,父類別中任何屬性的值,都會被子類別中相同屬性的新執行個體覆寫。
宣告屬性類別
在套用 AttributeUsageAttribute 之後,即可開始定義屬性的細節。 如下列程式碼所示,屬性類別的宣告看起來類似傳統類別的宣告:
[AttributeUsage(AttributeTargets::Method)]
public ref class MyAttribute : Attribute
{
// . . .
};
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
// . . .
}
<AttributeUsage(AttributeTargets.Method)>
Public Class MyAttribute
Inherits Attribute
' . . .
End Class
這個屬性的定義會顯示下列要點:
屬性類別必須宣告為公用類別。
依慣例,屬性類別的名稱會以這個字 Attribute結尾。 雖然並非必要,不過建議您遵照這個慣例以提高可讀性。 當屬性已套用時,要不要包含 Attribute 這個字都可以。
所有的屬性類別都必須直接或間接繼承自 System.Attribute 類別。
在 Microsoft Visual Basic 中,所有自訂屬性的類別都必須有 System.AttributeUsageAttribute 屬性。
宣告建構函式
就如同傳統的類別一樣,屬性會使用建構函式進行初始化。 下列程式碼片段說明典型的屬性建構函式。 這個公用建構函式會接受一個參數並將其值設定為等於成員變數。
MyAttribute(bool myvalue)
{
this->myvalue = myvalue;
}
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
Public Sub New(myvalue As Boolean)
Me.myvalue = myvalue
End Sub
您可以多載建構函式以容納不同的值組合。 如果您也為自訂的屬性類別定義 屬性 ,您可以在初始化屬性時使用具名和位置參數的組合。 通常您會將所有必要的參數定義為位置,而所有選擇性參數則定義為名稱。 在此情況下,屬性沒有必要的參數就無法初始化。 所有其他參數皆為選擇性使用。
注意
在 Visual Basic 中,屬性類別的建構函式不應使用 ParamArray
引數。
下列程式碼範例示範如何使用選擇性和必要的參數,來套用使用先前建構函示的屬性。 這項作業會假設屬性有一個必要的布林值和一個選擇性的字串屬性。
// 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
{
//...
};
// 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 Class SomeClass
'...
End Class
' One required (positional) parameter is applied.
<MyAttribute(false)>
Public Class SomeOtherClass
'...
End Class
宣告屬性
如果您想要定義具名的參數或提供簡單的方式,來傳回屬性所儲存的值,請宣告 屬性。 屬性的屬性應該宣告為公用實體,並具有將傳回之資料類型的描述。 定義會保存您屬性值的變數,並將其與 get
和 set
方法建立關聯。 下列程式碼範例示範如何在您的屬性中實作屬性:
property bool MyProperty
{
bool get() {return this->myvalue;}
void set(bool value) {this->myvalue = value;}
}
public bool MyProperty
{
get {return this.myvalue;}
set {this.myvalue = value;}
}
Public Property MyProperty As Boolean
Get
Return Me.myvalue
End Get
Set
Me.myvalue = Value
End Set
End Property
自訂屬性範例
本節包含先前的資訊,並說明如何設計屬性,記錄某一段程式碼的作者相關資訊。 此範例中的屬性儲存程式設計人員的名字和層級,以及此程式碼是否經過審閱。 它會使用三個私用變數來儲存要儲存的實際值。 每個變數都會以取得和設定值的公用屬性來表示。 最後,建構函式會以兩個必要參數來定義:
[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;}
}
};
[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 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
您可以用下列其中一種方式,也就是使用完整名稱 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)>
第一個範例會顯示僅套用必要具名參數的屬性。 第二個範例會顯示以必要和選擇性參數套用的屬性。