Share via


Skriva anpassade attribut

Om du vill utforma anpassade attribut behöver du inte lära dig många nya begrepp. Om du är bekant med objektorienterad programmering och vet hur du utformar klasser har du redan de flesta av de kunskaper som behövs. Anpassade attribut är traditionella klasser som härleds direkt eller indirekt från System.Attribute klassen. Precis som traditionella klasser innehåller anpassade attribut metoder som lagrar och hämtar data.

De primära stegen för att utforma anpassade attributklasser korrekt är följande:

Det här avsnittet beskriver vart och ett av dessa steg och avslutas med ett exempel på ett anpassat attribut.

Tillämpa attributetUsageAttribute

En anpassad attributdeklaration börjar med System.AttributeUsageAttribute attributet, som definierar några av de viktigaste egenskaperna för din attributklass. Du kan till exempel ange om attributet kan ärvas av andra klasser eller vilka element som attributet kan tillämpas på. Följande kodfragment visar hur du AttributeUsageAttributeanvänder :

[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

Har AttributeUsageAttribute tre medlemmar som är viktiga för att skapa anpassade attribut: AttributeTargets, Inherited och AllowMultiple.

AttributeTargets-medlem

I föregående exempel AttributeTargets.All anges som anger att det här attributet kan tillämpas på alla programelement. Du kan också ange AttributeTargets.Class, som anger att attributet endast kan tillämpas på en klass, eller AttributeTargets.Method, som anger att attributet endast kan tillämpas på en metod. Alla programelement kan markeras som beskrivning av ett anpassat attribut på det här sättet.

Du kan också skicka flera AttributeTargets värden. Följande kodfragment anger att ett anpassat attribut kan tillämpas på alla klasser eller metoder:

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

Ärvd egenskap

Egenskapen AttributeUsageAttribute.Inherited anger om attributet kan ärvas av klasser som härleds från de klasser som attributet tillämpas på. Den här egenskapen tar antingen en true (standard) eller false flagga. I följande exempel MyAttribute har ett standardvärde Inheritedtrue, medan YourAttribute har värdet Inheritedfalse:

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

De två attributen tillämpas sedan på en metod i basklassen 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

Slutligen ärvs klassen YourClass från basklassen MyClass. Metoden MyMethod visar MyAttribute men inte 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

Egenskapen AllowMultiple

Egenskapen AttributeUsageAttribute.AllowMultiple anger om flera instanser av attributet kan finnas på ett element. Om värdet trueär är flera instanser tillåtna. Om värdet false är (standard) tillåts endast en instans.

I följande exempel MyAttribute har ett standardvärde AllowMultiplefalse, medan YourAttribute har värdet 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

När flera instanser av dessa attribut tillämpas skapar MyAttribute du ett kompilatorfel. Följande kodexempel visar giltig användning av YourAttribute och ogiltig användning av 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

Om både AllowMultiple egenskapen och Inherited egenskapen är inställda på truekan en klass som ärvs från en annan klass ärva ett attribut och ha en annan instans av samma attribut som används i samma underordnade klass. Om AllowMultiple är inställt på falseskrivs värdena för alla attribut i den överordnade klassen över av nya instanser av samma attribut i den underordnade klassen.

Deklarera attributklassen

När du har tillämpat AttributeUsageAttributebörjar du definiera egenskaperna för attributet. Deklarationen av en attributklass ser ut ungefär som deklarationen för en traditionell klass, vilket visas i följande kod:

[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

Den här attributdefinitionen visar följande punkter:

  • Attributklasser måste deklareras som offentliga klasser.

  • Enligt konventionen slutar namnet på attributklassen med ordet Attribut. Även om den inte krävs rekommenderas den här konventionen för läsbarhet. När attributet tillämpas är inkluderingen av ordet Attribut valfritt.

  • Alla attributklasser måste ärva direkt eller indirekt från System.Attribute klassen.

  • I Microsoft Visual Basic måste alla anpassade attributklasser ha attributet System.AttributeUsageAttribute .

Deklarera konstruktorer

Precis som traditionella klasser initieras attribut med konstruktorer. Följande kodfragment illustrerar en typisk attributkonstruktor. Den här offentliga konstruktorn tar en parameter och anger en medlemsvariabel som är lika med dess värde.

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

Du kan överbelasta konstruktorn för att hantera olika kombinationer av värden. Om du också definierar en egenskap för din anpassade attributklass kan du använda en kombination av namngivna och positionella parametrar när du initierar attributet. Normalt definierar du alla obligatoriska parametrar som positionella och alla valfria parametrar som namngivna. I det här fallet kan attributet inte initieras utan den obligatoriska parametern. Alla andra parametrar är valfria.

Kommentar

I Visual Basic bör konstruktorer för en attributklass inte använda ett ParamArray argument.

I följande kodexempel visas hur ett attribut som använder den tidigare konstruktorn kan användas med hjälp av valfria och obligatoriska parametrar. Det förutsätter att attributet har ett obligatoriskt booleskt värde och en valfri strängegenskap.

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

Deklarera egenskaper

Om du vill definiera en namngiven parameter eller ge ett enkelt sätt att returnera de värden som lagras av attributet deklarerar du en egenskap. Attributegenskaper ska deklareras som offentliga entiteter med en beskrivning av den datatyp som ska returneras. Definiera variabeln som ska innehålla värdet för din egenskap och associera den med get metoderna och set . Följande kodexempel visar hur du implementerar en egenskap i attributet:

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

Exempel på anpassat attribut

Det här avsnittet innehåller föregående information och visar hur du utformar ett attribut som dokumenterar information om författaren till ett kodavsnitt. Attributet i det här exemplet lagrar programmerarens namn och nivå och om koden har granskats. Den använder tre privata variabler för att lagra de faktiska värdena som ska sparas. Varje variabel representeras av en offentlig egenskap som hämtar och anger värdena. Slutligen definieras konstruktorn med två obligatoriska parametrar:

[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

Du kan använda det här attributet med det fullständiga namnet , DeveloperAttributeeller med det förkortade namnet , Developerpå något av följande sätt:

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

Det första exemplet visar attributet som tillämpas med endast de obligatoriska namngivna parametrarna. Det andra exemplet visar attributet som tillämpas med både obligatoriska och valfria parametrar.

Se även