Кратко съдържание


Дефиниране на собствени атрибути



страница51/73
Дата21.07.2018
Размер9.03 Mb.
#76887
1   ...   47   48   49   50   51   52   53   54   ...   73

Дефиниране на собствени атрибути


До момента разгледахме какво представляват атрибутите и как се ползват атрибути, дефинирани стандартно в .NET Framework или дефинирани от други разработчици. Сега ще разгледаме как можем да дефини­раме собствени атрибути, които да използваме за свои специфични цели: например, когато разработваме сървърни приложения или компоненти.

За да бъде създаден потребителски атрибут, той задължително трябва да наследява класа System.Attribute и на компилатора трябва да се укаже към какъв вид елементи от кода може да се прилага атрибутът, т.е. какви са неговите цели. Това става с помощта на мета-атрибута AttributeUsage.


Собствени атрибути – пример


Да разгледаме следния пример: в даден проект има изискване всеки клас да съдържа в себе си информация за своя автор. Една възможност да се реализира това е във всеки един от класовете да се сложи коментар, подобен на този:

// This class is written by Person X.

За четящия кода ще бъде ясно кой е авторът, но няма да е възможно тази информация да се извлича по време на изпълнение на програмата, след като сорс кодът е бил вече компилиран.

За да решим този проблем, можем вместо горния коментар да ползваме специален атрибут:



[Author("Person X")]

Въпреки че има само функциите на коментар, този атрибут може да бъде извличан от метаданните програмно чрез специално създадени за това инструменти. Ако използваме подобен атрибут, ще бъде възможно, при настъпване на изключение в нашата програма, да изведем информация не само в кой метод и кой клас е настъпило то, но също и кой е авторът на кода, в който е възникнал проблемът. Това би могло да бъде полезно при неговото решаване.

Дефиниране на собствен атрибут – пример


Нека сега дефинираме нашия атрибут за автор. Както вече отбелязахме, всички атрибути са инстанции на класове, а всеки клас, дефиниращ собствен атрибут, наследява класа System.Attribute. В нашия случай, когато създаваме атрибут, съдържащ името на автора на класа, можем да използваме следната дефиниция:

public class AuthorAttribute: System.Attribute { … }

Както имената на вградените атрибути, така и имената на потреби­тел­ските атрибути трябва да завършват с окончанието Attribute (по възпри­етата в .NET Framework конвенция за имената).

Следващото нещо, което е необходимо, за да стане нашият клас AuthorAttribute потребителски атрибут, е да му приложим атрибута AttributeUsage. Чрез него указваме кои са целите, към които може да се прилага, и дали се допуска многократно прилагане към една и съща цел.

За да е възможно подаването на параметър при създаването на атрибута, за него трябва да се дефинира и подходящ конструктор.

Следва примерна реализация на атрибута AuthorAttribute:



using System;
[AttributeUsage(AttributeTargets.Struct |

AttributeTargets.Class | AttributeTargets.Interface)]

public class AuthorAttribute: System.Attribute

{

private string mName;


public AuthorAttribute(string aName)

{

mName = aName;



}
public string Name

{

get



{

return mName;

}

}

}



Както се вижда от декларацията, нашият атрибут може да се прилага само към структури, класове и интерфейси, като към дадена цел не може да се прилага повече от веднъж (това се подразбира ако не е указано друго).

Понеже нашият атрибут е клас, който има само един конструктор, един­ственият начин да го инстанцираме е, като извикаме този конструктор. Следователно при използване на нашия атрибут винаги трябва да подаваме позиционния параметър за име на автор.

И така, веднъж деклариран, нашият атрибут вече може да бъде прилаган като всички останали атрибути:

[Author("Светлин Наков")]

class CustomAttributesDemo

{



}



В примера към класа CustomAttributesDemo е приложен AuthorAttribute, който задава автор Светлин Наков.

Ако се опитаме да приложим AuthorAttribute няколко пъти към една и съща цел или да го приложим без параметри, ще получим грешка по време на компилация.

До момента дефинирахме и приложихме свой собствен атрибут, но защо ни беше това? Печелим възможността да добавяме допълнителна инфор­мация към елементи от кода и да я извличаме на по-късен етап от вече компилирания код. Възниква въпросът как точно става това извличане.

Извличане на атрибути от асембли


По време на изпълнение на програмата може да се използва следният код, за да се извлече атрибутът, приложен върху класа CustomAttributesDemo от горния пример:

string className = "CustomAttributesDemo";

Assembly ass = Assembly.GetExecutingAssembly();

Type type = ass.GetType(className);

object[] allAttributes = type.GetCustomAttributes(false);

AuthorAttribute author = allAttributes[0] as AuthorAttribute;

Console.WriteLine("Class {0} is written by {1}. ",

className, author.Name);


В примера първо се взема текущото асембли, от него се изваждат метаданните за класа CustomAttributesDemo, след което се извличат всички атрибути, приложени към този клас. Накрая се взема първият атрибут от списъка и се преобразува до тип AuthorAttribute. Както се вижда, извлеченият атрибут е най-обикновена инстанция на класа AuthorAttribute и тя може да се използва така, сякаш е създадена в момента, а не е извлечена от асемблито.

Горният пример използва технологията "reflection" (отражение на типо­вете), на която ще обърнем по-голямо внимание в съответната тема. Засега е достатъчно да знаем, че има лесен начин атрибутите да бъдат извличани по време на изпълнение на приложението.


Мета-атрибутът AttributeUsage


Вече се сблъскахме с атрибута AttributeUsage в предходния пример. Нека сега си изясним по-детайлно за какво служи той и кога се използва.

AttributeUsage е системен атрибут, който се прилага към декларациите на други атрибути. В този смисъл той е мета-атрибут, т.е. предоставя метаданни за атрибутите (мета-метаданни).

Когато се използва AttributeUsage, на конструктора се подават два аргумента. Първият от тях е набор от флагове, указващи допустимите цели, (например класове и структури), а вторият (AllowMultiple) е булев флаг, указващ дали е допустимо към дадена цел да се приложи повече от една инстанция на дефинирания атрибут.

Следва пример, в който се дефинира атрибут, който служи за добавяне на коментари в кода, които, за разлика от обикновените коментари, при компилация не се губят, а се запазват в компилираните асемблита:

[AttributeUsage(AttributeTargets.All, AllowMultiple=true)]

public class CommentAttribute: System.Attribute

{

private string mCommentText;


public CommentAttribute(string aCommentText)

{

mCommentText = aCommentText;



}
public string CommentText

{

get



{

return mCommentText;

}

}

}



Коментарите, дефинирани чрез горния атрибут, могат да се прикрепят към всякакви цели: асембли, тип, метод, поле, свойство и др., като към всяка цел може да се добавя повече от един коментар. Следва пример за използването на CommentAttribute:

using System;
[assembly: Comment("This is a test assembly!")]
[Comment("This class is for test purposes only.")]

[Comment("(C) Svetlin Nakov, 2005. All rights reserved!")]

class TestCommentAttribute

{

[Comment("The name of the configuration file.")]



public static string CONFIG_FILE_NAME = "config.xml";
[Comment("This is the program entry point.")]

static void Main()

{

...


}

}


Коментарите, прикрепени към кода по този начин, могат да се извличат от компилирания код и да се използват от приложението по време на изпълнение или от различни инструменти за работа с кода, като дебъгери, оптимизатори (execution profilers) и други.



Сподели с приятели:
1   ...   47   48   49   50   51   52   53   54   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница