Kenmerken
Kenmerken bieden een krachtige manier om metagegevens of declaratieve informatie te koppelen aan code (assembly's, typen, methoden, eigenschappen, enzovoort). Nadat u een kenmerk aan een programma-entiteit hebt gekoppeld, kunt u tijdens runtime een query uitvoeren op het kenmerk met behulp van een techniek met de naam weerspiegeling.
Kenmerken hebben de volgende eigenschappen:
- Kenmerken voegen metagegevens toe aan uw programma. Metagegevens is informatie over de typen die in een programma zijn gedefinieerd. Alle .NET-assembly's bevatten een opgegeven set metagegevens waarmee de typen en typeleden worden beschreven die in de assembly zijn gedefinieerd. U kunt aangepaste kenmerken toevoegen om eventuele andere vereiste informatie op te geven.
- Kenmerken kunnen worden toegepast op volledige assembly's, modules of kleinere programma-elementen, zoals klassen en eigenschappen.
- Kenmerken kunnen argumenten op dezelfde manier accepteren als methoden en eigenschappen.
- Met kenmerken kan een programma zijn eigen metagegevens of metagegevens in andere programma's onderzoeken met behulp van weerspiegeling.
Werken met reflectie
Reflectie API's die worden geleverd door Type assembly's, modules en typen beschrijven. U kunt reflectie gebruiken om dynamisch een exemplaar van een type te maken, het type aan een bestaand object te binden of het type op te halen uit een bestaand object en de methoden ervan aan te roepen of toegang te krijgen tot de velden en eigenschappen. Wanneer u attributen in uw code gebruikt, stelt reflectie u in staat om daar toegang toe te krijgen. Zie Kenmerkenvoor meer informatie.
Hier volgt een eenvoudig voorbeeld van weerspiegeling met de methode GetType(). Alle typen van de Object
basisklasse nemen deze methode over, die wordt gebruikt om het type variabele te verkrijgen:
Notitie
Zorg ervoor dat u de using System;
- en using System.Reflection;
-instructies boven aan het codebestand C# (.cs) toevoegt.
// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
De uitvoer toont het type:
System.Int32
In het volgende voorbeeld wordt reflectie gebruikt om de volledige naam van de geladen assembly te achterhalen.
// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);
De uitvoer is vergelijkbaar met het volgende voorbeeld:
System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
Verschillen tussen trefwoorden voor IL
De C#-trefwoorden protected
en internal
hebben geen betekenis in Tussenliggende taal (IL) en worden niet gebruikt in de reflectie-API's. De bijbehorende termen in IL zijn Family en Assembly. Hier volgen enkele manieren waarop u deze voorwaarden kunt gebruiken:
- Als u een
internal
methode wilt identificeren met behulp van weerspiegeling, gebruikt u de eigenschap IsAssembly. - Gebruik de
protected internal
om een IsFamilyOrAssembly methode te identificeren.
Werken met attributen
Kenmerken kunnen op vrijwel elke declaratie worden geplaatst, hoewel een specifiek kenmerk de typen declaraties kan beperken waarop deze geldig is. In C# geeft u een kenmerk op door de naam van het kenmerk tussen vierkante haken ([]
) te plaatsen boven de declaratie van de entiteit waarop het van toepassing is.
In dit voorbeeld gebruikt u het kenmerk SerializableAttribute om een specifiek kenmerk toe te passen op een klasse:
[Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
U kunt een methode declareren met het kenmerk DllImportAttribute:
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
U kunt meerdere kenmerken op een declaratie plaatsen:
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
Sommige kenmerken kunnen meerdere keren worden opgegeven voor een bepaalde entiteit. In het volgende voorbeeld ziet u een multiuse van het kenmerk ConditionalAttribute:
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}
Notitie
Standaard eindigen alle kenmerknamen met het achtervoegsel 'Kenmerk' om ze te onderscheiden van andere typen in de .NET-bibliotheken. U hoeft echter niet het kenmerkachtervoegsel op te geven wanneer u kenmerken in code gebruikt. Een [DllImport]
-declaratie is bijvoorbeeld gelijk aan een [DllImportAttribute]
-declaratie, maar DllImportAttribute
is de werkelijke naam van de klasse in de .NET-klassebibliotheek.
Kenmerkparameters
Veel kenmerken hebben parameters, die kunnen worden positionele, naamlozeof met de naam. In de volgende tabel wordt beschreven hoe u werkt met benoemde en positionele kenmerken:
positionele parameters
Parameters van de kenmerkconstructor:
benoemde parameters
Eigenschappen of velden van het kenmerk:
- Moet specificeren, mag niet weglaten
- Altijd eerst specificeren
- Opgeven in bepaalde volgorde
- Altijd optioneel, weglaten wanneer onwaar
- Geef op na positieparameters
- Opgeven in een willekeurige volgorde
De volgende code toont bijvoorbeeld drie equivalente DllImport
kenmerken:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
De eerste parameter, de DLL-naam, is positioneel en komt altijd als eerste. De andere instanties zijn benoemde parameters. In dit scenario worden beide benoemde parameters standaard ingesteld op false, zodat ze kunnen worden weggelaten. Raadpleeg de documentatie van het afzonderlijke kenmerk voor informatie over standaardparameterwaarden. Zie het gedeelte Kenmerken van de C#-taalspecificatievoor meer informatie over toegestane parametertypen.
Doelen voor attributen
Het doel van een kenmerk is de entiteit waarop het kenmerk van toepassing is. Een kenmerk kan bijvoorbeeld worden toegepast op een klasse, een methode of een assembly. Een kenmerk is standaard van toepassing op het element dat hierop volgt. Maar u kunt ook expliciet het element identificeren dat moet worden gekoppeld, zoals een methode, een parameter of de retourwaarde.
Gebruik de volgende syntaxis om expliciet een kenmerkdoel te identificeren:
[target : attribute-list]
In de volgende tabel ziet u de lijst met mogelijke target
waarden.
Doelwaarde | Van toepassing op |
---|---|
assembly |
Hele montage |
module |
Huidige assemblagemodule |
field |
Veld in een klasse of een structuur |
event |
Gebeurtenis |
method |
Methode ofwel get en set eigenschapstoegangsaccessors |
param |
Methodeparameter(s) of set eigenschapstoegangsparameter(s) |
property |
Eigendom |
return |
Retourwaarde van een methode, eigenschapsindexeerfunctie of get eigenschapstoegangsfunctie |
type |
Struct, klasse, interface, opsomming of gedelegeerde |
U kunt de field
doelwaarde opgeven om een kenmerk toe te passen op het backingveld dat is gemaakt voor een automatisch geïmplementeerde eigenschap.
In het volgende voorbeeld ziet u hoe u kenmerken toepast op assembly's en modules. Zie Common attributes (C#)voor meer informatie.
using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
In het volgende voorbeeld ziet u hoe u kenmerken toepast op methoden, methodeparameters en waarden voor het retourneren van methoden in C#.
// default: applies to method
[ValidatedContract]
int Method1() { return 0; }
// applies to method
[method: ValidatedContract]
int Method2() { return 0; }
// applies to parameter
int Method3([ValidatedContract] string contract) { return 0; }
// applies to return value
[return: ValidatedContract]
int Method4() { return 0; }
Notitie
Ongeacht de doelen waarop het kenmerk ValidatedContract
is gedefinieerd, moet het return
doel worden opgegeven, zelfs als het kenmerk ValidatedContract
is gedefinieerd om alleen op retourwaarden toe te passen. Met andere woorden, de compiler gebruikt de AttributeUsage
informatie niet om dubbelzinnige kenmerkdoelen op te lossen. Zie AttributeUsagevoor meer informatie.
Manieren bekijken om kenmerken te gebruiken
Hier volgen enkele veelvoorkomende manieren om kenmerken in code te gebruiken:
- Markeer controllermethoden die reageren op POST-berichten met behulp van het kenmerk
HttpPost
. Zie de HttpPostAttribute klas voor meer informatie. - Beschrijf hoe u parameters van de marshal-methode gebruikt bij het samenwerken met systeemeigen code. Zie de MarshalAsAttribute klas voor meer informatie.
- COM-eigenschappen (Component Object Model) beschrijven voor klassen, methoden en interfaces.
- Roep niet-beheerde code aan met behulp van de klasse DllImportAttribute.
- Beschrijf uw assembly in termen van titel, versie, beschrijving of handelsmerk.
- Beschrijven welke leden van een klasse moeten worden geserialiseerd voor persistentie.
- Beschrijf hoe u een toewijzing kunt maken tussen klasseleden en XML-knooppunten voor XML-serialisatie.
- Beschrijf de beveiligingsvereisten voor methoden.
- Geef kenmerken op die worden gebruikt om beveiliging af te dwingen.
- Controleer optimalisaties met de Just-In-Time-compiler (JIT) zodat de code gemakkelijk te debuggen blijft.
- Informatie over de aanroeper voor een methode verkrijgen.
Scenario's voor reflectie bekijken
Weerspiegeling is handig in de volgende scenario's:
- Toegang tot kenmerken in de metagegevens van uw programma. Zie Gegevens ophalen die zijn opgeslagen in kenmerkenvoor meer informatie.
- Bekijk en instantieer typen in een assembly.
- Bouw nieuwe typen tijdens runtime met behulp van klassen in de System.Reflection.Emit naamruimte.
- Voer late bindings- en toegangsmethoden uit voor typen die tijdens runtime zijn gemaakt. Zie Dynamisch laden en typengebruiken voor meer informatie.