Wpisywanie atrybutów niestandardowych

Aby zaprojektować własne atrybuty niestandardowe, nie trzeba tworzyć wielu nowych pojęć. Jeśli znasz programowanie obiektowe i wiesz, jak projektować klasy, masz już większość potrzebnej wiedzy. Atrybuty niestandardowe są zasadniczo tradycyjnymi klasami, które pochodzą bezpośrednio lub pośrednio od System.Attribute klasy . Podobnie jak w przypadku tradycyjnych klas, atrybuty niestandardowe zawierają metody, które przechowują i pobierają dane.

Podstawowe kroki prawidłowego projektowania klas atrybutów niestandardowych są następujące:

W tej sekcji opisano każdy z tych kroków i na koniec przedstawiono przykładowy atrybut niestandardowy.

Stosowanie atrybutu AttributeUsageAttribute

Deklaracja atrybutu niestandardowego rozpoczyna się od , która definiuje niektóre kluczowe System.AttributeUsageAttribute cechy klasy atrybutów. Można na przykład określić, czy atrybut może być dziedziczony przez inne klasy, lub określić, do których elementów można zastosować atrybut. Poniższy fragment kodu pokazuje, jak używać funkcji 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

Element ma trzy elementy członkowskie, które są ważne dla tworzenia atrybutów AttributeUsageAttribute niestandardowych: AttributeTargets, Inheritedi AllowMultiple.

AttributeTargets, członek

W poprzednim przykładzie AttributeTargets.All określono wartość , co oznacza, że ten atrybut może być stosowany do wszystkich elementów programu. Alternatywnie można określić wartość , wskazującą, że atrybut może być stosowany tylko do klasy lub , wskazując, że atrybut może być stosowany tylko AttributeTargets.Class AttributeTargets.Method do metody. W ten sposób wszystkie elementy programu mogą być oznaczone do opisu za pomocą atrybutu niestandardowego.

Można również przekazać wiele AttributeTargets wartości. Poniższy fragment kodu określa, że atrybut niestandardowy można zastosować do dowolnej klasy lub metody.

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

Właściwość dziedziczona

Właściwość wskazuje, czy atrybut może być dziedziczony przez klasy pochodzące z klas, AttributeUsageAttribute.Inherited do których zastosowano atrybut. Ta właściwość przyjmuje flagę true (domyślną) lub false . W poniższym przykładzie MyAttribute element ma wartość domyślną , a Inherited element ma wartość 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

Te dwa atrybuty są następnie stosowane do metody w klasie bazowej 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

Na koniec klasa YourClass jest dziedziczona z klasy bazowej MyClass . Metoda wyświetla MyMethod MyAttribute , ale nie 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, właściwość

Właściwość wskazuje, czy w elemencie może istnieć AttributeUsageAttribute.AllowMultiple wiele wystąpień atrybutu. Jeśli ustawiono wartość , dozwolone jest wiele wystąpień; jeśli jest ustawiona wartość true false (wartość domyślna), dozwolone jest tylko jedno wystąpienie.

W poniższym przykładzie wartość domyślna to , a wartość MyAttribute AllowMultiple to 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

Zastosowanie wielu wystąpień tych atrybutów MyAttribute powoduje wystąpienie błędu kompilatora. Poniższy przykład kodu przedstawia prawidłowe użycie i YourAttribute nieprawidłowe użycie . 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

Jeśli zarówno właściwość, jak i właściwość są ustawione na , klasa dziedziczona z innej klasy może dziedziczyć atrybut i mieć inne wystąpienie tego samego atrybutu zastosowane w tej samej klasie AllowMultiple Inherited true podrzędnej. Jeśli jest ustawiona na , wartości atrybutów w klasie nadrzędnej zostaną zastąpione przez nowe wystąpienia tego samego atrybutu AllowMultiple false w klasie podrzędnej.

Deklarowanie klasy atrybutów

Po zastosowaniu AttributeUsageAttribute atrybutu można rozpocząć definiowanie określonych atrybutów. Deklaracja klasy atrybutu wygląda podobnie do deklaracji klasy tradycyjnej, jak pokazano w poniższym kodzie.

[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

Ta definicja atrybutu demonstruje następujące kwestie:

  • Klasy atrybutów muszą być zadeklarowane jako klasy publiczne.

  • Zgodnie z konwencją nazwa klasy atrybutów kończy się wyrazem Atrybut. Chociaż nie jest to wymagane, ta konwencja jest zalecana w celu zachowania czytelności. Po zastosowaniu atrybutu dołączenie słowa Atrybut jest opcjonalne.

  • Wszystkie klasy atrybutów muszą dziedziczyć bezpośrednio lub pośrednio z System.Attribute klasy .

  • W programie Microsoft Visual Basic wszystkie klasy atrybutów niestandardowych muszą mieć System.AttributeUsageAttribute atrybut .

Deklarowanie konstruktorów

Atrybuty są inicjowane za pomocą konstruktorów w taki sam sposób jak tradycyjne klasy. Poniższy fragment kodu ilustruje typowy konstruktor atrybutu. Ten publiczny konstruktor pobiera parametr i ustawia zmienną członkowski równą jej wartości.

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

Konstruktor można przeciążyć w celu uwzględnienia różnych kombinacji wartości. Jeśli zdefiniujesz również właściwość dla klasy atrybutów niestandardowych, podczas inicjowania atrybutu można użyć kombinacji parametrów nazwanych i pozyskich. Zazwyczaj wszystkie wymagane parametry definiuje się jako parametry pozyacyjne, a wszystkie parametry opcjonalne jako nazwane. W takim przypadku nie można zainicjować atrybutu bez wymaganego parametru. Wszystkie inne parametry są opcjonalne. Należy pamiętać, Visual Basic konstruktory klasy atrybutu nie powinny używać argumentu ParamArray.

Poniższy przykład kodu pokazuje, jak można zastosować atrybut używający poprzedniego konstruktora przy użyciu parametrów opcjonalnych i wymaganych. Przyjęto założenie, że atrybut ma jedną wymaganą wartość logiczną i jedną opcjonalną właściwość ciągu.

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

Deklarowanie właściwości

Jeśli chcesz zdefiniować nazwany parametr lub zapewnić łatwy sposób zwracania wartości przechowywanych przez atrybut, zadeklaruj właściwość. Właściwości atrybutów powinny być zadeklarowane jako jednostki publiczne z opisem typu danych, który zostanie zwrócony. Zdefiniuj zmienną, która będzie przechowywać wartość właściwości, i skojarz ją z metodami get i set. W poniższym przykładzie kodu pokazano, jak zaimplementować prostą właściwość w atrybutze .

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

Przykład atrybutu niestandardowego

Ta sekcja zawiera poprzednie informacje i pokazuje, jak zaprojektować prosty atrybut, który dokumentuje informacje o autorze sekcji kodu. Atrybut w tym przykładzie przechowuje nazwę i poziom programisty oraz to, czy kod został przejmowany. Używa trzech zmiennych prywatnych do przechowywania rzeczywistych wartości do zapisania. Każda zmienna jest reprezentowana przez właściwość publiczną, która pobiera i ustawia wartości. Na koniec konstruktor jest definiowany z dwoma wymaganymi parametrami.

[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

Ten atrybut można zastosować przy użyciu pełnej nazwy lub skróconej nazwy ( ) w DeveloperAttribute Developer jeden z następujących sposobów.

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

W pierwszym przykładzie pokazano atrybut zastosowany tylko z wymaganymi nazwanych parametrów, a w drugim przykładzie pokazano atrybut zastosowany zarówno z parametrami wymaganymi, jak i opcjonalnymi.

Zobacz też