Любой компилятор может
поместить информацию обо всех элементах языка в создаваемый исполняемый файл
(делает он это или нет, другой вопрос). Однако добавить что-либо к этой
информации программист не может. Другими словами, при желании можно узнать, как
называется то или иное поле класса и данные какого типа оно хранит, какие методы
есть у класса и т.д. Но узнать из программы кто и когда последний раз
редактировал метод или получить описание на русском языке назначения поля класса
уже нельзя. Эта информация чаще всего относилась к категории комментариев в коде
программы, которые компилятор просто пропускает. Именно нишу дополнительной,
определяемой программистом, информации о коде программы в среде .NET
заняли атрибуты.
Атрибуты позволяют программистам добавлять к декларации основных структурных
элементов языка (сборки, классы, поля, методы, параметры методов и др.) своего
рода «комментарии», – произвольно структурированные данные, определяемые в
момент написания программы или программной библиотеки и сохраняемые компилятором
совместно с метаданными в готовом коде. Таким образом, атрибуты существенно
увеличивают возможности по использованию анализа метаданных средствами рефлексии
и фактически выводят пользу от такого анализа на принципиально новый уровень.
Сама среда программирования
Visual Studio
и компиляторы языков в
среде .NET
в большом объеме
пользуются атрибутами для описания правил обращения с элементами программ.
Например, стандартный атрибут
ConditionalAttribute
указывает компилятору
C#,
что метод помеченный этим атрибутом (а также все его вызовы) должны
присутствовать в программе только в том случае, если определен специальный
идентификатор, имя которого указывается в конструкторе атрибута. Если же
идентификатор с таким именем на момент компиляции программы не определен, то сам
метод и все его вызовы «изымаются» из кода программы, что достаточно широко
используется при отладке.
Для создания собственного
атрибута необходимо описать новый класс наследник класса
Attribute,
определить в нем необходимые поля и свойства для хранения информации и набор
конструкторов для его инициализации:
public
class TrustMethodAttribute : Attribute {
private int _trustLevel;
public int TrustLevel { get { return _trustLevel; } }
public TrustMethodAttribute(int trustLevel) {
this._trustLevel = trustLevel;
}
}
Имея готовый атрибут, можно
применять его для различных элементов языка:
[TrustMethod(4)]
public
void FooMethod(int param1) { … }
Для контроля использования
самого атрибута, в том числе для каких элементов языка может применяться
созданный атрибут и будет ли он автоматически наследоваться при его применении
для пользовательских классов, необходимо использовать атрибут
AttributeUsageAttribute
с соответствующими параметрами.
Для анализа того,
какие атрибуты применены к программной единице, нужно воспользоваться методами
GetCustomAttribute(s)
базового абстрактного класса
MemberInfo.
На основании полученных данных можно принимать решения о дальнейшем поведении
алгоритма. В том числе и с использованием данных, хранимых в атрибуте. |