撰寫自訂屬性Writing Custom Attributes

若要設計您自己的自訂屬性,並不需要精通很多新概念。To design your own custom attributes, you do not need to master many new concepts. 假如您擅長物件導向的程式設計,且瞭解如何設計類別,那麼您就已經擁有大部分所需的知識。If you are familiar with object-oriented programming and know how to design classes, you already have most of the knowledge needed. 自訂屬性基本上是一種直接或間接衍生自 System.Attribute的傳統類別。Custom attributes are essentially traditional classes that derive directly or indirectly from System.Attribute. 自訂屬性就像傳統類別一樣,含有儲存和擷取資料的方法。Just like traditional classes, custom attributes contain methods that store and retrieve data.

正確設計自訂屬性的主要步驟如下:The primary steps to properly design custom attribute classes are as follows:

本節會一一說明每個步驟,並於結尾提供 自訂屬性範例This section describes each of these steps and concludes with a custom attribute example.

套用 AttributeUsageAttributeApplying the AttributeUsageAttribute

自訂屬性宣告的開頭為 System.AttributeUsageAttribute,它定義您屬性類別的一些主要特性。A custom attribute declaration begins with the System.AttributeUsageAttribute, which defines some of the key characteristics of your attribute class. 例如,您可以指定屬性是否可由其他類別繼承或指定屬性可以套用至哪一個項目。For example, you can specify whether your attribute can be inherited by other classes or specify which elements the attribute can be applied to. 下列程式碼片段示範如何使用 AttributeUsageAttributeThe following code fragment demonstrates how to use the 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 有三個建立自訂屬性所需的重要成員:AttributeTargetsInheritedAllowMultipleThe AttributeUsageAttribute has three members that are important for the creation of custom attributes: AttributeTargets, Inherited, and AllowMultiple.

AttributeTargets 成員AttributeTargets Member

在上述範例中,指定了 AttributeTargets.All ,指出此屬性可以套用到所有程式元素。In the previous example, AttributeTargets.All is specified, indicating that this attribute can be applied to all program elements. 或者,您也可以指定 AttributeTargets.Class,指出您的屬性可以套用到類別,或指定 AttributeTargets.Method,指出屬性只能套用至方法。Alternatively, you can specify AttributeTargets.Class, indicating that your attribute can be applied only to a class, or AttributeTargets.Method, indicating that your attribute can be applied only to a method. 所有的程式項目都可以用這種方式透過自訂屬性標示為描述。All program elements can be marked for description by a custom attribute in this manner.

您也可以傳遞多個 AttributeTargets 值。You can also pass multiple AttributeTargets values. 下列程式碼片段指定自訂屬性可以套用至任何類別或方法。The following code fragment specifies that a custom attribute can be applied to any class or method.

[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
    Inherits Attribute
    '...
End Class

Inherited 屬性Inherited Property

AttributeUsageAttribute.Inherited 屬性會指出,衍生自套用您屬性之類別的類別,是否可繼承您的屬性。The AttributeUsageAttribute.Inherited property indicates whether your attribute can be inherited by classes that are derived from the classes to which your attribute is applied. 此屬性會接受 true (預設值) 或 false 旗標。This property takes either a true (the default) or false flag. 在下列範例中,MyAttribute 的預設 Inherited 值為 true,而 YourAttributeInherited 值為 falseIn the following example, MyAttribute has a default Inherited value of true, while YourAttribute has an Inherited value of 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 中的方法。The two attributes are then applied to a method in the base 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 繼承類別 MyClassFinally, the class YourClass is inherited from the base class MyClass. 此方法 MyMethod 顯示 MyAttribute,但不是 YourAttributeThe method MyMethod shows MyAttribute, but not 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 屬性AllowMultiple Property

AttributeUsageAttribute.AllowMultiple 屬性會指出項目上是否可以有您屬性的多個執行個體。The AttributeUsageAttribute.AllowMultiple property indicates whether multiple instances of your attribute can exist on an element. 如果設定為 true,則允許多個執行個體;如果設定為 false (預設值),則只允許一個執行個體。If set to true, multiple instances are allowed; if set to false (the default), only one instance is allowed.

在下列範例中,MyAttribute 有預設的 AllowMultiplefalse,而 YourAttributetrue 的值。In the following example, MyAttribute has a default AllowMultiple value of false, while YourAttribute has a value of 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 會產生編譯器錯誤。When multiple instances of these attributes are applied, MyAttribute produces a compiler error. 下列程式碼範例示範有效的 YourAttribute 用法和無效的 MyAttribute 用法。The following code example shows the valid use of YourAttribute and the invalid use of 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,繼承自另一個類別的類別可以繼承屬性,並在同一個子類別中套用同一屬性的另一個執行個體。If both the AllowMultiple property and the Inherited property are set to true, a class that is inherited from another class can inherit an attribute and have another instance of the same attribute applied in the same child class. 如果 AllowMultiple 設定為 false,父類別中任何屬性的值,都會被子類別中相同屬性的新執行個體覆寫。If AllowMultiple is set to false, the values of any attributes in the parent class will be overwritten by new instances of the same attribute in the child class.

宣告屬性類別Declaring the Attribute Class

在套用 AttributeUsageAttribute之後,您可以開始定義屬性的細節。After you apply the AttributeUsageAttribute, you can begin to define the specifics of your attribute. 如下列程式碼所示,屬性類別的宣告看起來類似傳統類別的宣告。The declaration of an attribute class looks similar to the declaration of a traditional class, as demonstrated by the following code.

[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

這個屬性的定義會顯示下列要點:This attribute definition demonstrates the following points:

  • 屬性類別必須宣告為公用類別。Attribute classes must be declared as public classes.

  • 依慣例,屬性類別的名稱會以這個字 Attribute結尾。By convention, the name of the attribute class ends with the word Attribute. 雖然並非必要,不過建議您遵照這個慣例以提高可讀性。While not required, this convention is recommended for readability. 當屬性已套用時,要不要包含 Attribute 這個字都可以。When the attribute is applied, the inclusion of the word Attribute is optional.

  • 所有的屬性類別必須直接或間接繼承自 System.AttributeAll attribute classes must inherit directly or indirectly from System.Attribute.

  • 在 Microsoft Visual Basic 中,所有自訂屬性的類別都必須有 System.AttributeUsageAttribute 屬性。In Microsoft Visual Basic, all custom attribute classes must have the System.AttributeUsageAttribute attribute.

宣告建構函式Declaring Constructors

屬性使用建構函式進行初始化的方式,與傳統的類別相同。Attributes are initialized with constructors in the same way as traditional classes. 下列程式碼片段說明典型的屬性建構函式。The following code fragment illustrates a typical attribute constructor. 這個公用建構函式會接受一個參數並將其值設定為等於成員變數。This public constructor takes a parameter and sets a member variable equal to its value.

MyAttribute(bool myvalue)
{
    this->myvalue = myvalue;
}
public MyAttribute(bool myvalue)
{
    this.myvalue = myvalue;
}
Public Sub New(myvalue As Boolean)
    Me.myvalue = myvalue
End Sub

您可以多載建構函式以容納不同的值組合。You can overload the constructor to accommodate different combinations of values. 如果您也為自訂的屬性類別定義 屬性 ,您可以在初始化屬性時使用具名和位置參數的組合。If you also define a property for your custom attribute class, you can use a combination of named and positional parameters when initializing the attribute. 通常您會將所有必要的參數定義為位置,而所有選擇性參數則定義為名稱。Typically, you define all required parameters as positional and all optional parameters as named. 在此情況下,屬性沒有必要的參數就無法初始化。In this case, the attribute cannot be initialized without the required parameter. 所有其他參數皆為選擇性使用。All other parameters are optional. 請注意在 Visual Basic 中,屬性類別的建構函式不應使用 ParamArray 引數。Note that in Visual Basic, constructors for an attribute class should not use a ParamArray argument.

下列程式碼範例示範如何使用選擇性和必要的參數,來套用使用先前建構函示的屬性。The following code example shows how an attribute that uses the previous constructor can be applied using optional and required parameters. 這項作業會假設屬性有一個必要的布林值和一個選擇性的字串屬性。It assumes that the attribute has one required Boolean value and one optional string property.

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

宣告屬性Declaring Properties

如果您想要定義具名的參數或提供簡單的方式,來傳回屬性所儲存的值,請宣告 屬性If you want to define a named parameter or provide an easy way to return the values stored by your attribute, declare a property. 屬性的屬性應該宣告為公用實體,並具有將傳回之資料類型的描述。Attribute properties should be declared as public entities with a description of the data type that will be returned. 定義會保存您屬性值的變數,並將其與 getset 方法建立關聯。Define the variable that will hold the value of your property and associate it with the get and set methods. 下列程式碼範例示範如何在您的屬性中實作簡單的屬性。The following code example demonstrates how to implement a simple property in your attribute.

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

自訂屬性範例Custom Attribute Example

本節包含先前的資訊,並說明如何設計簡單的屬性,記錄某一段程式碼的作者相關資訊。This section incorporates the previous information and shows how to design a simple attribute that documents information about the author of a section of code. 此範例中的屬性儲存程式設計人員的名字和層級,以及此程式碼是否經過審閱。The attribute in this example stores the name and level of the programmer, and whether the code has been reviewed. 它會使用三個私用變數來儲存要儲存的實際值。It uses three private variables to store the actual values to save. 每個變數都會以取得和設定值的公用屬性來表示。Each variable is represented by a public property that gets and sets the values. 最後,建構函式會以兩個必要參數來定義。Finally, the constructor is defined with two required parameters.

[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,來套用此屬性。You can apply this attribute using the full name, DeveloperAttribute, or using the abbreviated name, Developer, in one of the following ways.

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

第一個範例示範只套用了必要具名參數的屬性,而第二個範例則示範同時套用了必要和選擇性參數的屬性。The first example shows the attribute applied with only the required named parameters, while the second example shows the attribute applied with both the required and optional parameters.

另請參閱See also