Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базовые технологии платформы .NET.docx
Скачиваний:
11
Добавлен:
18.08.2019
Размер:
423.24 Кб
Скачать

26. Атрибуты

Платформа .NET позволяет расширять метаданные типов и сборок, используя систему атрибутов. Каждый атрибут (attribute) описывает дополнительную информацию, сохраняемую в метаданных для цели атрибута (attribute target) – сборки, модуля, типа, элементов типа, параметров метода. С точки зрения программиста атрибуту соответствует класса атрибута – это класс, наследуемый от System.Attribute.

Рассмотрим основные аспекты работы с атрибутами. Для создания атрибута нужно написать класс, удовлетворяющий перечисленным ниже требованиям:

1. Класс должен прямо или косвенно наследоваться от класса Attribute.

2. Тип открытых полей, свойств и параметров конструктора класса ограничен следующим набором: числовые типы (кроме decimal), bool, char, string, object, System.Type, перечисления; одномерные массивы указанных типов.

3. Имя класса должно заканчиваться суффиксом Attribute (это необязательное требование).

Приведём пример класса атрибута:

public class AuthorAttribute : Attribute

{

public string Name { get; private set; }

public string CreationDate { get; set; }

public AuthorAttribute(string name)

{

Name = name;

}

}

Для применения атрибута язык C# поддерживает следующий синтаксис: имя класса атрибута записывается в квадратных скобках перед тем элементом, к которому он относится. При этом разрешено указывать имя атрибута без суффикса Attribute. Применение атрибута условно соответствует созданию объекта. Поэтому после имени атрибута указываются в круглых скобках аргументы конструктора атрибута. Если у атрибута конструктор без параметров, круглые скобки можно не писать. Наряду с аргументами конструктора можно указать именованные параметры, предназначенные для задания значения открытого поля или свойства. Для этого используется синтаксис имя-элемента = значение. Именованные параметры всегда записываются в конце списка аргументов конструктора. Ниже приведены примеры применения AuthorAttribute.

[Author("Brian Kernighan", CreationDate = "01.01.2012")]

public class ColorPlugin

{

[Author("Dennis Ritchie")]

public void Process() { }

}

Для настройки создаваемого пользовательского атрибута можно использовать атрибут [AttributeUsage]. Конструктор [AttributeUsage] принимает единственный параметр – набор элементов перечисления AttributeTargets, определяющих цель атрибута. Булево свойство AllowMultiple определяет, может ли атрибут быть применён к программному элементу более одного раза. Булево свойство Inherited указывает, будет ли атрибут проецироваться на потомков программного элемента (по умолчанию значение свойства равно true).

// атрибут Author можно многократно применить к классу или методу

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,

AllowMultiple = true)]

public class AuthorAttribute : Attribute

{

// элементы класса для краткости не приводятся

}

Синтаксис применения атрибутов позволяет указать в квадратных скобках несколько атрибутов через запятую. Если возникает неоднозначность трактовки цели атрибута, то нужно указать перед именем атрибута специальный префикс – assembly, module, field, event, method, param, property, return, type.

// применение атрибута к сборке

[assembly: AssemblyKeyFile("keys.snk")]

// многократное применение атрибута

[Author("Brian Kernighan"), Author("Dennis Ritchie")]

public class ColorPlugin { }

Опишем возможности получения информации о применённых атрибутах. Метод Attribute.GetCustomAttributes() возвращает все атрибуты некоторого элемента в виде массива. Метод Attribute.GetCustomAttribute() получает атрибут заданного типа:

Attribute GetCustomAttribute(MemberInfo element, Type attributeType)

При помощи параметра element задаётся элемент, у которого надо получить атрибут. Второй параметр – это тип получаемого атрибута.

// пример получения атрибута

var author = Attribute.GetCustomAttribute(typeof (ColorPlugin),

typeof (AuthorAttribute));

if (author != null)

{

Console.WriteLine(((AuthorAttribute) author).Name);

}

Платформа .NET предоставляет для использования обширный набор атрибутов, некоторая часть которых представлена в табл. 19.

Таблица 19

Некоторые атрибуты, применяемые в платформе .NET

Атрибут

Цель применения

Описание

[AttributeUsage]

Класс

Задаёт область применения класса-атрибута

[Conditional]

Метод

Компилятор может игнорировать вызовы помеченного метода при заданном условии

[DllImport]

Метод

Импорт функций из DLL

[MTAThread]

Метод Main()

Для приложения используется модель COM Multithreaded apartment

[NonSerialized]

Поле

Указывает, что поле не будет сериализовано

[Obsolete]

Кроме param, assembly, module, return

Информирует, что в будущих реализациях данный элемент может отсутствовать

[ParamArray]

Параметр

Позволяет одиночному параметру быть обработанным как набор параметров params

[Serializable]

Класс, структура, перечисление, делегат

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

[STAThread]

Метод Main()

Для приложения используется модель COM Single-threaded apartment

[StructLayout]

Класс, структура

Задаёт схему размещения данных класса или структуры в памяти (Auto, Explicit, Sequential)

[ThreadStatic]

Статическое поле

В каждом потоке будет использоваться собственная копия данного статического поля

Рассмотрим единичный пример использования стандартных атрибутов. Атрибуты применяются для настройки взаимодействия программ платформы .NET и библиотек на неуправляемом коде. Атрибут [DllImport] предназначен для импортирования функций из библиотек динамической компоновки, написанных на неуправляемом коде. В следующей программе показан импорт системной функции MessageBoxA():

using System.Runtime.InteropServices;

public class MainClass

{

[DllImport("user32.dll")]

public static extern int MessageBoxA(int hWnd, string text,

string caption, uint type);

public static void Main()

{

MessageBoxA(0, "Hello World", "Unmanaged DLL", 0);

}

}

Для использования атрибута [DllImport] требуется подключить пространство имён System.Runtime.InteropServices. Кроме этого, необходимо объявить импортируемую функцию статической и пометить её модификатором extern. Атрибут [DllImport] допускает использование дополнительных аргументов, подробное описание которых можно найти в документации MSDN.

Исполняемая среда .NET выполняет корректную передачу аргументов примитивных типов между управляемым и неуправляемым кодом. Для правильной передачи сложных аргументов требуется использование специального атрибута [StructLayout] при объявлении пользовательского типа. Например, пусть выполняется экспорт системной функции GetLocalTime():

[DllImport("kernel32.dll")]

public static extern void GetLocalTime(SystemTime st);

В качестве параметра функция использует объект класса SystemTime. Этот класс должен быть описан следующим образом:

[StructLayout(LayoutKind.Sequential)]

public class SystemTime

{

public ushort wYear;

public ushort wMonth;

public ushort wDayOfWeek;

public ushort wDay;

public ushort wHour;

public ushort wMinute;

public ushort wSecond;

public ushort wMilliseconds;

}

Атрибут [StructLayout] с аргументом LayoutKind.Sequential указывает, что поля объекта должны быть расположены в памяти в точности так, как это записано в объявлении класса. В противном случае при работе с системной функцией вероятно возникновение ошибок.