Полное руководство. С# 4.0 - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
Как только класс атрибута будет определен, атрибут можно присоединить к элементу. Атрибут указывается перед тем элементом, к которому он присоединяется, идля этого его конструктор заключается в квадратные скобки. В качестве примера нижепоказано, как атрибут RemarkAttribute связывается с классом. [RemarkAttribute("В этом классе используется атрибут.")]class UseAttrib { // ...}
В этом фрагменте кода конструируется атрибут RemarkAttribute, содержащийкомментарий "В этом классе используется атрибут." Данный атрибут затемсвязывается с классом UseAttrib.
Присоединяя атрибут, совсем не обязательно указывать суффикс Attribute.Например, приведенный выше класс может быть объявлен следующим образом. [Remark("В этом классе используется атрибут.")]class UseAttrib { // ...}
В этом объявлении указывается только имя Remark. Такая сокращенная форма считается вполне допустимой, но все же надежнее указывать полное имя присоединяемого атрибута, чтобы избежать возможной путаницы и неоднозначности.Получение атрибутов объекта
Как только атрибут будет присоединен к элементу, он может быть извлечен в других частях программы. Для извлечения атрибута обычно используется один из двухметодов. Первый метод, GetCustomAttributes(), определяется в классе MemberInfои наследуется классом Туре. Он извлекает список всех атрибутов, присоединенных кэлементу. Ниже приведена одна из его форм.object[] GetCustomAttributes(bool наследование)
Если наследование имеет логическое значение true, то в список включаютсяатрибуты всех базовых классов, наследуемых по иерархической цепочке. В противномслучае атрибуты извлекаются только из тех классов, которые определяются указаннымтипом.
Второй метод, GetCustomAttribute(), определяется в классе Attribute. Нижеприведена одна из его форм:static Attribute GetCustomAttribute(MemberInfo элемент, Type тип_атрибута)
где элемент обозначает объект класса MemberInfo, описывающий тот элемент, для которого создаются атрибуты, тогда как тип_атрибута — требуемый атрибут. Данныйметод используется в том случае, если имя получаемого атрибута известно заранее, чтозачастую и бывает. Так, если в классе UseAttrib имеется атрибут RemarkAttribute,то для получения ссылки на этот атрибут можно воспользоваться следующей последовательностью кода.// Получить экземпляр объекта класса MemberInfо, связанного// с классом, содержащим атрибут RemarkAttribute.Type t = typeof(UseAttrib);// Извлечь атрибут RemarkAttribute.Type tRemAtt = typeof(RemarkAttribute);RemarkAttribute ra = (RemarkAttribute) Attribute.GetCustomAttribute(t, tRemAtt);
Эта последовательность кода оказывается вполне работоспособной, поскольку классMemberInfo является базовым для класса Туре. Следовательно, t — это экземпляробъекта класса MemberInfo.
Имея ссылку на атрибут, можно получить доступ к его членам. Благодаря этому информация об атрибуте становится доступной для программы, использующей элемент,к которому присоединен атрибут. Например, в следующей строке кода выводится содержимое свойства Remark.Console.WriteLine(rа.Remark);
Ниже приведена программа, в которой все изложенные выше особенности применения атрибутов демонстрируются на примере атрибута RemarkAttribute.// Простой пример применения атрибута.using System;using System.Reflection; [AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute { string pri_remark; // базовое поле свойства Remark public RemarkAttribute(string comment) { pri_remark = comment; } public string Remark { get { return pri_remark; } }} [RemarkAttribute("В этом классе используется атрибут.")]class UseAttrib { // ...}class AttribDemo { static void Main() { Type t = typeof(UseAttrib); Console.Write("Атрибуты в классе " + t.Name + ": "); object[] attribs = t.GetCustomAttributes(false); foreach(object о in attribs) { Console.WriteLine(o); } Console.Write("Примечание: "); // Извлечь атрибут RemarkAttribute. Type tRemAtt = typeof(RemarkAttribute); RemarkAttribute ra = (RemarkAttribute) Attribute.GetCustomAttribute(t, tRemAtt); Console.WriteLine(ra.Remark); }}
Эта программа дает следующий результат.Атрибуты в классе UseAttrib: RemarkAttributeПримечание: В этом классе используется атрибут.Сравнение позиционных и именованных параметров
В предыдущем примере для инициализации атрибута RemarkAttribute егоконструктору была передана символьная строка с помощью обычного синтаксисаконструктора. В этом случае параметр comment конструктора RemarkAttribute()называется позиционным. Этот термин отражает тот факт, что аргумент связан с параметром по его позиции в списке аргументов. Следовательно, первый аргумент передается первому параметру, второй аргумент — второму параметру и т.д.
Но для атрибута доступны также именованные параметры, которым можно присваивать первоначальные значения по их именам. В этом случае значение имеет имя,а не позиция параметра.
ПРИМЕЧАНИЕНесмотря на то что именованные параметры атрибутов, по существу, подобны именованным аргументам методов, они все же отличаются в деталях.
Именованный параметр поддерживается открытым полем или свойством, котороедолжно быть нестатическим и доступным только для записи. Любое поле или свойство подобного рода может автоматически использоваться в качестве именованногопараметра. Значение присваивается именованному параметру с помощью соответствующего оператора, расположенного в списке аргументов при вызове конструктораатрибута. Ниже приведена общая форма объявления атрибута, включая именованныепараметры.[attrib(список_позиционных_параметров, именованный_параметр_1 = значение, именованный_параметр_2 = значение, ...)]
Первыми указываются позиционные параметры, если они существуют. Далее следуют именованные параметры с присваиваемыми значениями. Порядок следованияименованных параметров особого значения не имеет. Именованным параметрам необязательно присваивать значение, и в этом случае используется значение, устанавливаемое по умолчанию.
Применение именованного параметра лучше всего показать на конкретном примере. Ниже приведен вариант класса RemarkAttribute, в который добавлено полеSupplement, предназначенное для хранения дополнительного примечания. [AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute { string pri remark; // базовое поле свойства Remark // Это поле можно использовать в качестве именованного параметра. public string Supplement; public RemarkAttribute(string comment) { pri_remark = comment; Supplement = "Отсутствует"; } public string Remark { get { return pri_remark; } }}
Как видите, поле Supplement инициализируется в конструкторе символьной строкой "Отсутствует". Другого способа присвоить ему первоначальное значение в конструкторе не существует. Но поскольку поле Supplement является открытым в классеRemarkAttribute, его можно использовать в качестве именованного параметра, какпоказано ниже. [RemarkAttribute("В этом классе используется атрибут.", Supplement = "Это дополнительная информация.")]class UseAttrib { // ...}
Обратите особое внимание на вызов конструктора класса RemarkAttribute. В этомконструкторе первым, как и прежде, указывается позиционный параметр, а за нимчерез запятую следует именованный параметр Supplement, которому присваиваетсяконкретное значение. И наконец, закрывающая скобка, ), завершает вызов конструктора. Таким образом, именованный параметр инициализируется в вызове конструктора.Этот синтаксис можно обобщить: позиционные параметры должны указываться в томпорядке, в каком они определены в конструкторе, а именованные параметры — в произвольном порядке и вместе с присваиваемыми им значениями.
Ниже приведена программа, в которой демонстрируется применение поляSupplement в качестве именованного параметра атрибута.// Использовать именованный параметр атрибута.using System;using System.Reflection;[AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute { string pri_remark; // базовое поле свойства Remark public string Supplement; // это именованный параметр public RemarkAttribute(string comment) { pri_remark = comment; Supplement = "Отсутствует"; } public string Remark { get { return pri_remark; } }}[RemarkAttribute("В этом классе используется атрибут.",Supplement = "Это дополнительная информация.")]class UseAttrib { // ...}class NamedParamDemo { static void Main() { Type t = typeof(UseAttrib); Console.Write("Атрибуты в классе " + t.Name + "); object[] attribs = t.GetCustomAttributes(false); foreach(object о in attribs) { Console.WriteLine(o); } // Извлечь атрибут RemarkAttribute. Type tRemAtt = typeof(RemarkAttribute); RemarkAttrib.ute ra = (RemarkAttribute) Attribute.GetCustomAttribute(t, tRemAtt); Console.Write("Примечание: "); Console.WriteLine(ra.Remark); Console.Write("Дополнение: ") ; Console.WriteLine(ra.Supplement); }}