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

25. Атрибуты

Помимо метаданных, в платформе .NET представлена система атрибутов. Атрибуты позволяют определить дополнительную информацию в метаданных, связанных с типом, и дают механизм для обращения к этой информации в ходе компиляции или выполнения программы.

Согласно синтаксису C#, чтобы использовать атрибут, нужно записать его имя в квадратных скобках перед тем элементом, к которому он относится. Разрешено указывать имя атрибута без суффикса Attribute, который обязателен для всех атрибутов. Можно задать в квадратных скобках несколько атрибутов через запятую. Если возникает неоднозначность трактовки цели атрибута, то нужно указать перед именем атрибута специальный префикс – assembly, module, field, event, method, param, property, return, type. Например, запись [assembly: AssemblyKeyFile] означает применение атрибута к сборке1. Любой атрибут является классом, производным от System.Attribute, а применение атрибута условно соответствует созданию объекта. Поэтому после имени атрибута указываются в круглых скобках аргументы конструктора атрибута. Если у атрибута конструктор без параметров, круглые скобки можно не писать.

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

Платформа .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", "nativeDLL", 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). В противном случае при работе с системной функцией вероятно возникновение ошибок.

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

    • Класс должен быть потомком класса System.Attribute.

    • Имя класса должно заканчиваться суффиксом Attribute1.

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

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

public class AuthorAttribute : Attribute

{

public string Name { get; private set; }

public string CreationDate { get; set; }

public AuthorAttribute(string name)

{

Name = name;

}

}

Далее можно применить атрибут [Author] к произвольному типу:

[Author("Developer")]

public class A { . . . }

[Author("Developer", CreationDate = "01.01.2010")]

public struct B { . . . }

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

Используем возможности класса AttributeUsageAttribute при описании пользовательского атрибута:

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

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,

AllowMultiple = true)]

public class AuthorAttribute : Attribute { . . . }

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

Attribute GetCustomAttribute(MemberInfo element, Type attributeType)

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

[Author("Developer", CreationDate = "01.01.2010")]

public class SomeClass { . . . }

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

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

typeof(AuthorAttribute));

if (author != null)

{

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

}

Следует иметь в виду, что объект, соответствующий классу атрибута, создаётся исполняющей средой только в тот момент, когда из атрибута извлекается информация. Задание атрибута перед некоторым элементом к созданию объекта не приводит. Количество созданных экземпляров атрибута равно количеству запросов к данным атрибута1.