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 Inherited på true
, 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 AllowMultiple på false
, 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å true
kan 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å false
skrivs 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 , DeveloperAttribute
eller med det förkortade namnet , Developer
på 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.