Platforma .NET definuje možnost asociovat libovolné informace (metadata) se zdrojovým kódem aplikace. Tyto metadata jsou reprezentovaná atribut. Po kompilaci se atributy stanou součástí assembly. V programu jsem schopni tyto metadata získat pomocí mechanismu reflexe.
Příklad: pokud chceme, aby nějaká třída (její instance) byla serializována (uložena na diskový prostor), vložíme před ni atribut Serializable:
[Serializable] class MyClass() ... |
Vytvoříme-li projekt pomocí Visual Studia.NET, vytvoří tento nástroj soubor AssemblyInfo.cs. Tento soubor obsahuje atributy vztahující se k celé assembly. Vygenerovaný soubor vypadá takto:
using System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile("")] [assembly: AssemblyKeyName("")] |
Dalším použivaným atributem je atribut Obsolete. Tento atribut signalizuje, že daná metoda je již zastaralá a nemá být používaná.
[Obsolete(message,bool)
message - vysvětlující text, který bude vypisovat překladač.
bool je true - použití metody je chyba při překladu.
bool je false - použití metody způsobí warning při překladu.
Představené příklady ukazují některé předdefinované atributy. Platforma .NET jich celou řadu. Interně jsou atributy realizovány pomocí tříd. Třída reprezentující atribut musí rozšiřovat System.Attribute. Tato třída je základní pro všechny atributy. V .NET Framework nejsou kladeny žádné omezení na množinu atributů. Uživatel může tuto množinu libovolně rozšiřovat. Atribut se skládá z parametrů. Existují dva typy parametrů.
Poziční parametry se zadávají jako formální parametry konstruktoru a jsou tudíž vždy povinné.
Pojmenované parametry se zadávají pomocí jména a operátoru přiřazení.
Atributy mohou také mít určité vlastnsoti. Tyto vlastnosti můžeme nastavit pomocí specifických atributů, které přidáme k definici našeho nového atributu.
[AttributeUsage(destination, AllowMultiple=bool, Inherited=bool)]
destination - typ cíle, pro který je atribut použitelný.
Lze povolit násobnou aplikaci.
Povolit dědičnost atributu.
Cíl atributu je dán výčtovým typem AttributeTargets.
Assembly, Class, Constructor, Delegate, Enum, Event, Field, Interface, Method, Parameter, Property, RetrurnValue, Struct, All.
Cíle lze kombinovat pomocí logického operátoru OR.
Následující příklad demonstruje použití atributu. Nejprve definujeme atribut MyAttribute. Tento atribut má poziční parametr Message a pojmenovaný paramet Number. Atribut je použitelný pouze u tříd a metod. Může být použit násobně a nelze jej dále rozšiřovat. Tyto vlastnosti jsem atributu dodali pomocí dalších specifických atributů. Použití je demonstrováno na jednoduché třídě. V metodě Main pak demonstrujeme získání zapsaných informací pomocí mechanismu reflexe.
using System; using System.Reflection; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple=true, Inherited=false)] class MyAttribute : Attribute { private string message; public MyAttribute(string message) { this.message=message; } int number; public int Number { get {return number;} set {number=value;} } public string Message { get {return this.message;} } } [MyAttribute("Simple class",Number=1)] [MyAttribute("but very nice!")] class Example { [MyAttribute("Stupid method",Number=10)] public void Test() {} } class RunApp { static void Main(string[] args) { Type example=typeof(Example); foreach(MyAttribute myAttribute in example.GetCustomAttributes(false)) Console.WriteLine("Class:"+myAttribute.Message+"("+myAttribute.Number+")"); foreach(MemberInfo member in example.GetMembers()) foreach(MyAttribute myAttribute in member.GetCustomAttributes(false)) Console.WriteLine("Member:"+myAttribute.Message+"("+myAttribute.Number+")"); } } |
Výstup programu bude:
Class:but very nice!(0) Class:Simple class(1) Member:Stupid method(10) |