Aangepaste kenmerken schrijven
Als u aangepaste kenmerken wilt ontwerpen, hoeft u niet veel nieuwe concepten te leren. Als u bekend bent met objectgeoriënteerde programmering en weet hoe u klassen ontwerpt, hebt u al de meeste kennis nodig. Aangepaste kenmerken zijn traditionele klassen die rechtstreeks of indirect zijn afgeleid van de System.Attribute klasse. Net als bij traditionele klassen bevatten aangepaste kenmerken methoden waarmee gegevens worden opgeslagen en opgehaald.
De primaire stappen voor het correct ontwerpen van aangepaste kenmerkklassen zijn als volgt:
In deze sectie wordt elk van deze stappen beschreven en wordt afgesloten met een voorbeeld van een aangepast kenmerk.
De AttributeUsageAttribute toepassen
Een aangepaste kenmerkdeclaratie begint met het System.AttributeUsageAttribute kenmerk, waarmee enkele van de belangrijkste kenmerken van uw kenmerkklasse worden gedefinieerd. U kunt bijvoorbeeld opgeven of uw kenmerk kan worden overgenomen door andere klassen of op welke elementen het kenmerk kan worden toegepast. Het volgende codefragment laat zien hoe u het AttributeUsageAttributevolgende gebruikt:
[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
De AttributeUsageAttribute groep bevat drie leden die belangrijk zijn voor het maken van aangepaste kenmerken: AttributeTargets, Overgenomen en AllowMultiple.
AttributeTargets Member
In het voorgaande voorbeeld AttributeTargets.All wordt opgegeven, waarmee wordt aangegeven dat dit kenmerk kan worden toegepast op alle programma-elementen. U kunt ook opgeven AttributeTargets.Class, waarmee wordt aangegeven dat uw kenmerk alleen op een klasse kan worden toegepast of AttributeTargets.Methoddat uw kenmerk alleen op een methode kan worden toegepast. Alle programma-elementen kunnen op deze manier worden gemarkeerd voor beschrijving door een aangepast kenmerk.
U kunt ook meerdere AttributeTargets waarden doorgeven. Het volgende codefragment geeft aan dat een aangepast kenmerk kan worden toegepast op elke klasse of methode:
[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
Inherits Attribute
'...
End Class
Overgenomen eigenschap
De AttributeUsageAttribute.Inherited eigenschap geeft aan of uw kenmerk kan worden overgenomen door klassen die zijn afgeleid van de klassen waarop uw kenmerk wordt toegepast. Deze eigenschap heeft een true
(de standaard) of false
vlag. In het volgende voorbeeld MyAttribute
heeft u een standaardwaarde Inherited van true
, terwijl YourAttribute
deze een Inherited waarde heeft van 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
De twee kenmerken worden vervolgens toegepast op een methode in de basisklasse 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
Ten slotte wordt de klasse YourClass
overgenomen van de basisklasse MyClass
. De methode MyMethod
toont MyAttribute
maar niet 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
Eigenschap AllowMultiple
De AttributeUsageAttribute.AllowMultiple eigenschap geeft aan of er meerdere exemplaren van uw kenmerk kunnen bestaan op een element. Als dit is ingesteld op true
, zijn meerdere exemplaren toegestaan. Als deze optie is ingesteld op false
(de standaardinstelling), is slechts één exemplaar toegestaan.
In het volgende voorbeeld MyAttribute
heeft u een standaardwaarde AllowMultiple van false
, terwijl YourAttribute
deze een waarde heeft van 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
Wanneer meerdere exemplaren van deze kenmerken worden toegepast, MyAttribute
wordt er een compilerfout gegenereerd. In het volgende codevoorbeeld ziet u het geldige gebruik van YourAttribute
en het ongeldige gebruik van 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
Als zowel de AllowMultiple eigenschap als de Inherited eigenschap zijn ingesteld op true
, kan een klasse die wordt overgenomen van een andere klasse een kenmerk overnemen en een ander exemplaar van hetzelfde kenmerk toepassen in dezelfde onderliggende klasse. Als AllowMultiple deze optie is ingesteld false
, worden de waarden van kenmerken in de bovenliggende klasse overschreven door nieuwe exemplaren van hetzelfde kenmerk in de onderliggende klasse.
De kenmerkklasse declareren
Nadat u het AttributeUsageAttributekenmerk hebt toegepast, begint u met het definiëren van de specifieke kenmerken van uw kenmerk. De declaratie van een kenmerkklasse lijkt op de declaratie van een traditionele klasse, zoals wordt gedemonstreerd door de volgende 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
Deze kenmerkdefinitie demonstreert de volgende punten:
Kenmerkklassen moeten worden gedeclareerd als openbare klassen.
Volgens de conventie eindigt de naam van de kenmerkklasse met het woord Kenmerk. Hoewel dit niet vereist is, wordt deze conventie aanbevolen voor leesbaarheid. Wanneer het kenmerk wordt toegepast, is de opname van het woord Kenmerk optioneel.
Alle kenmerkklassen moeten direct of indirect worden overgenomen van de System.Attribute klasse.
In Microsoft Visual Basic moeten alle aangepaste kenmerkklassen het System.AttributeUsageAttribute kenmerk hebben.
Constructors declareren
Net als bij traditionele klassen worden kenmerken geïnitialiseerd met constructors. Het volgende codefragment illustreert een typische kenmerkconstructor. Deze openbare constructor neemt een parameter en stelt een lidvariabele in die gelijk is aan de bijbehorende waarde.
MyAttribute(bool myvalue)
{
this->myvalue = myvalue;
}
public MyAttribute(bool myvalue)
{
this.myvalue = myvalue;
}
Public Sub New(myvalue As Boolean)
Me.myvalue = myvalue
End Sub
U kunt de constructor overbelasten voor verschillende combinaties van waarden. Als u ook een eigenschap definieert voor uw aangepaste kenmerkklasse, kunt u een combinatie van benoemde en positionele parameters gebruiken bij het initialiseren van het kenmerk. Normaal gesproken definieert u alle vereiste parameters als positionele en alle optionele parameters als benoemd. In dit geval kan het kenmerk niet worden geïnitialiseerd zonder de vereiste parameter. Alle andere parameters zijn optioneel.
Notitie
In Visual Basic mogen constructors voor een kenmerkklasse geen argument gebruiken ParamArray
.
In het volgende codevoorbeeld ziet u hoe een kenmerk dat gebruikmaakt van de vorige constructor kan worden toegepast met optionele en vereiste parameters. Hierbij wordt ervan uitgegaan dat het kenmerk één vereiste Booleaanse waarde en één optionele tekenreekseigenschap heeft.
// 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
Eigenschappen declareren
Als u een benoemde parameter wilt definiëren of een eenvoudige manier wilt bieden om de waarden te retourneren die zijn opgeslagen door uw kenmerk, declareert u een eigenschap. Kenmerkeigenschappen moeten worden gedeclareerd als openbare entiteiten met een beschrijving van het gegevenstype dat wordt geretourneerd. Definieer de variabele die de waarde van uw eigenschap bevat en koppel deze aan de get
en set
methoden. In het volgende codevoorbeeld ziet u hoe u een eigenschap in uw kenmerk implementeert:
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
Voorbeeld van aangepast kenmerk
Deze sectie bevat de vorige informatie en laat zien hoe u een kenmerk ontwerpt dat informatie over de auteur van een codesectie documenteert. Het kenmerk in dit voorbeeld slaat de naam en het niveau van de programmeur op en of de code is gecontroleerd. Er worden drie privévariabelen gebruikt om de werkelijke waarden op te slaan om op te slaan. Elke variabele wordt vertegenwoordigd door een openbare eigenschap waarmee de waarden worden opgehaald en ingesteld. Ten slotte wordt de constructor gedefinieerd met twee vereiste 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
U kunt dit kenmerk op een van de volgende manieren toepassen met behulp van de volledige naam, DeveloperAttribute
of met behulp van de verkorte naam 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)>
In het eerste voorbeeld ziet u het kenmerk dat wordt toegepast met alleen de vereiste benoemde parameters. In het tweede voorbeeld ziet u het kenmerk dat is toegepast met zowel de vereiste als optionele parameters.