Опубликован: 01.11.2004 | Уровень: для всех | Доступ: свободно | ВУЗ: Московский государственный университет имени М.В.Ломоносова
Лекция 17:

C#. Индексаторы класса и атрибуты

< Лекция 16 || Лекция 17: 1234 || Лекция 18 >

Позиционные и именованные параметры атрибута

При назначении классу или члену класса атрибута используется конструктор атрибута со списком параметров. Параметры могут быть:

  • позиционными;
  • именованными.

Позиционные параметры указываются в порядке, который определяется списком параметров конструктора атрибута. Позиционные параметры всегда должны быть указаны при назначении атрибута.

Именованные параметры отсутствуют в списке параметров конструктора атрибута. Значения, задаваемые для именованных параметров, используются для инициализации полей и свойств создаваемого экземпляра атрибута. Список именованных параметров указывается через запятую после списка позиционных параметров. Каждый именованный параметр определяется как Имя_параметра=Значение_параметра.

В предыдущем примере параметр name использовался как позиционный параметр, а kod - как именованный (по умолчанию значение переменной kod, доступной через свойство Kod, устанавливается равным конкретному значению. Если при назначении атрибута явно не будет задан именованный параметр, то при создании экземпляра атрибута будет использовано значение по умолчанию).

Параметры атрибута могут указываться константными значениями следующих типов:

  • bool, byte, char, short, int, long, float, double;
  • string;
  • System.Type;
  • enums;
  • object (аргумент для параметра атрибута типа object должен быть константным значением вышеуказанных типов);
  • одноразмерные массивы любых вышеуказанных типов.

Используемость атрибута

Атрибуты могут быть использованы для различных элементов языка. Для того чтобы специфицировать, каким образом и для каких элементов можно использовать данный класс атрибута, библиотека NET Framework предоставляет класс System.AttributeUsageAttribute.

Спецификация используемости атрибута указывается в квадратных скобках перед именем определением класса.

Например:

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

Элементы языка, которым может быть назначен атрибут, указываются значением или набором значений перечислимого типа AttributeTargets.

Например, для использования данного атрибута только для классов или методов перед определением класса атрибута следует записать:

[AttributeUsage (AttributeTargets.Class | 
      AttributeTargets.Method)]

Спецификация используемости атрибута имеет следующее формальное описание:

[AttributeUsage(
  доступные_элементы,
  AllowMultiple=true_или_false,
  Inherited=наследуемость
)]

Доступные элементы определяют те элементы языка, для которых может быть назначен данный атрибут. По умолчанию используется значение AttributeTargets.All (доступен для всех элементов).

Если именованный параметр AllowMultiple равен true, то классу или члену класса может быть назначено несколько атрибутов.

Параметр Inherited определяет, наследуется ли данный атрибут производным классом (по умолчанию - false ).

Перечислимый тип AttributeTargets определяет следующее множество значений:

  • All - все элементы языка;
  • Assembly - сборки;
  • Class - классы;
  • Constructor - конструкторы;
  • Field - поля;
  • Method - методы;
  • Property - свойства;
  • Delegate - делегаты;
  • Enum - нумераторы;
  • Event - события;
  • Interface - интерфейсы;
  • Module - модули;
  • Parameter - параметры;
  • ReturnValue - возвращаемые значения;
  • Struct - структуры.

Доступ к атрибуту

Значения атрибутов или их существование могут быть запрошены во время выполнения приложения.

При запросе для класса или для члена класса данных о прикрепленных к нему атрибутах применяется отражение. Отражением называется функция, используемая во время выполнения приложения для получения метаданных, в том числе и заданных атрибутами.

Для реализации отражения библиотека NET Framework предоставляет несколько классов, базовым для которых служит класс отражения System.Reflection.

Основные методы отражения, используемые для запроса атрибутов, предоставляются классами System.Reflection.MemberInfo и System.Reflection.Assembly. Так, метод GetCustomAttributes позволяет определить атрибуты, присущие данному объекту.

Например:

class MyClass 
{ 
public static void Main() 
{
  System.Reflection.MemberInfo info = 
                typeof(MyClass);
  object[] attr = info.GetCustomAttributes(true);
  for (int i = 0; i < attr.Length; i ++)
    {  System.Console.WriteLine(attr[i]);  }
  }
}

В результате выполнения данного кода в массив будут помещены классы всех назначенных атрибутов, а также класс System.Reflection.DefaultMemberAttribute. Доступ к типу объекта может быть реализован посредством класса Type. Метод Object.GetType возвращает объект типа Type, представляющий тип экземпляра объекта. Объект типа Type представляет собой ассоциированный с типом объект, используемый для доступа к метаданным типа.

Используя класс Type, можно создать объект для типа, экземпляр которого еще не был создан.

Например:

Type t= typeof(MyClass1);

Для создания объекта типа, ассоциированного с типом существующего экземпляра объекта, следует использовать метод GetType.

Например:

Type t = obj1.GetType(); , где obj1 экземпляр класса MyClass1.

При использовании объекта типа атрибута метод GetCustomAttribute возвращает значения атрибута, который назначен указанному параметрами объекту: первый параметр метода определяет ассоциированный объект, а второй - указывает класс атрибута.

Например:

MyAttribute MyAttr = 
        (MyAttribute) Attribute.GetCustomAttribute(
                                 t, 
                                 typeof(MyAttribute));

Следующий пример иллюстрирует доступ к значениям атрибутов.

class Class1
{ static void Main(string[] args)
   {
 // Создание объекта, ассоциированного с типом AClass1
  Type t= typeof(AClass1);     
      MyAttribute MyAttr = 
        (MyAttribute) Attribute.GetCustomAttribute(
                                t, 
                                typeof (MyAttribute));
    if(null == MyAttr) 
      {Console.WriteLine("Атрибут не найден");}
    else 
        {
       Console.WriteLine("Атрибут name = {0}, 
        атрибут kod = {1}" , 
        MyAttr.Name,    // Возвращает значение 
                // поля Name атрибута MyAttribute
        MyAttr.Kod); }
   }
}
[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : System.Attribute
{  private string name;
  private int kod;
  public MyAttribute(string name)
          {this.name = name; this.kod = 10; }
  public  string Name { get { return name;} }
  public  int Kod { get { return kod; }
                    set {kod=value;   }   }
}

[My("NameOfClass", Kod=123)]
public class AClass1
{ public AClass1() { }
  private int [] iArr = new int[10]; 
  public int this[int ind1] {
                get { return iArr[ind1];}
                set { iArr[ind1]= value; }  }
}
Листинг 17.1.
< Лекция 16 || Лекция 17: 1234 || Лекция 18 >
Александр Демьяненко
Александр Демьяненко

Можно ли сдавать один и тот же тест несколько раз?
Или же один и тот же тест можно сдать лишь однажды?

Максим Стогний
Максим Стогний

Добрый день!

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

тип_метода (имя_класса::*имя_метода_указателя)
    (список параметров);
тип_функции (*имя_ функции_указателя)
    (список параметров);

при этом можно было  тип_функции во втором описании заменить на тип_метода? Т.е.:

тип_метода (*имя_ метода_указателя)
    (список параметров);