Г. Шилдт - Полный справочник по C# (1160789), страница 88
Текст из файла (страница 88)
В противномслучае будут включены только атрибуты, определенные заданным типом.Второй — метод GetCustomAttribute О , который определен в классе A t t r i b u t e .Вот один из форматов его вызова:s t a t i c Attribute GetCustomAttribute(Memberlnfo mi,Type attrib type)Здесь аргумент mi означает объект класса Memberlnfo, описывающий элемент, длякоторого извлекается атрибут. Нужный атрибут указывается аргументомattribtype.Этот метод используется в том случае, если известно имя атрибута, который нужнополучить.
Например, чтобы получить ссылку на атрибут RemarkAttribute, можноиспользовать такую последовательность:// Считываем RemarkAttribute.Type tRemAtt = typeof(RemarkAttribute);RemarkAttribute ra = (RemarkAttribute)Attribute.GetCustomAttribute(t, tRemAtt);Глава 17. Динамическая идентификация типов, отражение и атрибуты475Имея ссылку на атрибут, можно получить доступ к его членам. Другими словами,информация, связанная с атрибутом, доступна программе, использующей элемент, ккоторому присоединен атрибут.
Например, при выполнении следующей инструкцииотображается значение поля remark:I Console.WriteLine(ra.remark);Использование атрибута Rema r kAt t r i b u t e демонстрируется в приведенной нижепрограмме.// Простой пример атрибута.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 {public 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("Remark: " ) ;// Считываем атрибут RemarkAttribute.Type tRemAtt = typeof(RemarkAttribute);RemarkAttribute ra = (RemarkAttribute)Attribute.GetCustomAttribute(t, tRemAtt);Console.WriteLine(ra.remark);IРезультаты выполнения этой программы таковы:Атрибуты в UseAttrib: RemarkAttributeRemark: Этот класс использует атрибут.476Часть I.
Язык С #Сравнение позиционных и именованных параметровВ предыдущем примере атрибут Remark At t r i b u t e был инициализирован посредством передачи конструктору строки описания. В этом случае, т.е. при использованииобычного синтаксиса конструктора, параметр comment, принимаемый конструкторомRemarkAttribute (), называется позиционным параметром. Возникновение этого термина объясняется тем, что аргумент метода связывается с параметром посредствомсвоей позиции. Так работают в С# все методы и конструкторы. Но для атрибутовможно создавать именованные параметры и присваивать им начальные значения, используя их имена.Именованный параметр поддерживается либо открытым полем, либо свойством,которое не должно быть предназначено только для чтения. Такое поле или свойствоавтоматически можно использовать в качестве именованного параметра. При определении атрибута для элемента именованный параметр получает значение с помощьюинструкции присваивания, которая содержится в конструкторе атрибута.
Формат спецификации атрибута, включающей именованные параметры, таков:[ a t trib (список_позиционных_параметров,именованный_параметр__1 = value,именованный_параметр_2 = value, . . . ) ]Позиционные параметры (если они имеются) должны стоять в начале списка параметров. Затем каждому именованному параметру присваивается значение. Порядокследования именованных параметров не имеет значения. Именованным параметрамприсваивать значения необязательно. Но в данном случае значения инициализациииспользованы по назначению.Чтобы понять, как используются именованные параметры, лучше всего рассмотреть пример.
Перед вами версия определения класса RemarkAttribute, в которуюдобавлено поле supplement, позволяющее хранить дополнительный комментарий.[AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute {s t r i n g pri_remark; // Базовое поле для свойства remark.public s t r i n g supplement; // Это именованный параметр.public RemarkAttribute(string comment) {pri_remark = comment;supplement = "Данные отсутствуют";}public string remark {get {return pri_remark;Как видите, поле supplement инициализируется строкой "Данные отсутствуют" вконструкторе класса.
С помощью конструктора невозможно присваивоить этому полюдругое начальное значение. Однако, как показано в следующем фрагменте кода, полеsupplement можно использовать в качестве именованного параметра:[RemarkAttribute("Этот класс использует атрибут.",supplement = "Это дополнительная информация.")]class UseAttrib {Глава 17. Динамическая идентификация типов, отражение и атрибуты477Обратите особое внимание на то, как вызывается конструктор классаRemarkAttribute. Сначала задается позиционный аргумент.
За ним, после запятой,следует именованный параметр supplement, которому присваивается значение. Обращение к конструктору завершает закрывающая круглая скобка. Таким образом,именованный параметр инициализируется внутри вызова конструктора. Этот синтаксис можно обощить. Итак, позиционные параметры необходимо задавать в порядке,который определен конструктором. Именованные параметры задаются посредствомприсваивания значений их именам.Рассмотрим программу, которая демонстрирует использование поля supplement:// Использование именованного параметра атрибута.using System;using System.Reflection;[AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute {string pri__remark; / / Базовое поле для свойства remark.public s t r i n g supplement; / / Это именованный параметр.public RemarkAttribute(string comment) {pri_remark = comment;supplement = "Данные отсутствуют";public string remark {get {return pri_remark;[RemarkAttribute("Этот класс использует атрибут.",supplement = "Это дополнительная информация.")]class UseAttrib {class NamedParamDemo {public s t a t i c void Main() {Type t = typeof(UseAttrib);Console.Write("Атрибутыв " + t.Name + " : ") ;object[] a t t r i b s = t.GetCustomAttributes(false);foreach(object о in a t t r i b s ) {Console.WriteLine(o);// Считывание атрибута RemarkAttribute.Type tRemAtt = typeof(RemarkAttribute);RemarkAttribute ra = (RemarkAttribute)Attribute.GetCustomAttribute(t, tRemAtt);Console.Write("Remark: ") ;Console.WriteLine(ra.remark);478Часть I.
Язык С#Console.Write("Supplement: " ) ;Console.WriteLine(ra.supplement);IВот результаты выполнения этой программы:Атрибуты в UseAttrib: RemarkAttributeRemark: Этот класс использует атрибут.Supplement: Это дополнительная информация.Как разъяснялось выше, в качестве именованного параметра можно также использовать свойство. Например, в следующей программе в класс атрибутаjlema r kAt tribute добавляется int-свойство с именем priority.// Использование свойства в качестве именованного// параметра атрибута.using System;using System.Reflection;[AttributeUsage(AttributeTargets.All)]public class RemarkAttribute : Attribute {string pri__remark; // Базовое поле для свойства remark.int pri_priority; // Базовое поле для свойства priority,public string supplement; // Это именованный параметр.public RemarkAttribute(string comment) {pri_remark = comment;supplement = "Данные отсутствуют";}public string remark {get {return pri_remark;// Используем свойство в качестве именованного параметра,public int priority {get {return prijpriority;}set {prijpriority = value;}[RemarkAttribute("Этот класс использует атрибут.",supplement = "Это дополнительная информация.",priority = 10)]class UseAttrib {class NamedParamDemo {Глава 17.
Динамическая идентификация типов, отражение и атрибуты479public 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);RemarkAttribute ra = (RemarkAttribute)Attribute.GetCustomAttribute(t, tRemAtt);Console.Write("Remark: " ) ;Console.WriteLine(ra.remark);Console.Write("Supplement: " ) ;Console.WriteLine(ra.supplement);Console.WriteLine("Priority: " + ra.priority);Вот результаты выполнения этой программы:Атрибуты в UseAttrib: RemarkAttributeRemark: Этот класс использует атрибут.Supplement: Это дополнительная информация.Priority: 10Обратите внимание на определение атрибута (перед определением класса UseAttrib):[RemarkAttribute("Этот класс использует атрибут.",supplement = "Это дополнительная информация.",priority = 10)]Задание именованных атрибутов supplement и p r i o r i t y не подчинено определенному порядку.
Эти два присваивания можно поменять местами, и это никак неотразится на атрибуте в целом.-J Использование встроенных атрибутовВ С# определено три встроенных атрибута: AttributeUsage, Conditional иObsolete. Рассмотрим их по порядку.Атрибут AttributeUsageКак упоминалось выше, атрибут AttributeUsage определяет типы элементов, ккоторым можно применить атрибут. AttributeUsage — это еще одно имя для классаSystem.AttributeUsageAttribute.
В классе AttributeUsage определен следующий конструктор:AttributeUsage(AttributeTargets item)480Часть I. Язык С#Здесь параметр item означает элемент или элементы, к которым может быть применен этот атрибут. Тип A t t r i b u t e T a r g e t s — это перечисление, которое определяетследующие значения:AllAssemblyClassConstructorDelegateEnumEventFieldInterfaceMethodModuleParameterPropertyReturnValueStructДва или больше из этих значений можно объединить с помощью операции ИЛИ.Например, чтобы определить атрибут, применяемый только к полям и свойствам, используйте следующий вариант объединения значений перечисления AttributeTargets:1 AttributeTargets.Field | AttributeTargets.PropertyКонструктор класса AttributeUsage поддерживает два именованных параметра.Первый — это параметр AllowMultiple, который принимает значение типа bool.Если оно истинно, этот атрибут можно применить к одному элементу более одногораза.