寫入自訂屬性

若要設計自訂屬性,您並不需要了解很多新概念。 假如您擅長物件導向的程式設計,且了解如何設計類別,那麼您就已經擁有大部分所需的知識。 自訂屬性是一種直接或間接衍生自 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 有三個建立自訂屬性所需的重要成員:AttributeTargetsInheritedAllowMultiple

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,而 YourAttributeInherited 值為 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 有預設的 AllowMultiplefalse,而 YourAttributetrue 的值:

//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

宣告屬性

如果您想要定義具名的參數或提供簡單的方式,來傳回屬性所儲存的值,請宣告 屬性。 屬性的屬性應該宣告為公用實體,並具有將傳回之資料類型的描述。 定義會保存您屬性值的變數,並將其與 getset 方法建立關聯。 下列程式碼範例示範如何在您的屬性中實作屬性:

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)>

第一個範例會顯示僅套用必要具名參數的屬性。 第二個範例會顯示以必要和選擇性參數套用的屬性。

另請參閱