В .NET Framework разработчики имеют возможность определять собственные атрибуты. Атрибуты дают возможность задать информацию, которая будет применяться, практически к любой записи таблицы метаданных. Информацию об этих метаданных можно запрашивать во время выполнения программы, с целью изменения хода её выполнения.
Настраиваемые атрибуты применяются в большинстве технологий .NET Framework (WPF, Windows Forms, WCF…), однако, довольно длительное время, я использовал только стандартные атрибуты, которых, к слову, огромное множество, но всё же иногда приходится задавать свои собственные…
Наибольшую пользу собственные атрибуты могут принести, при использовании рефлексии. В этом случае код будет читать метаданные и выполнять действия в зависимости от их значения.
Создадим простой атрибут, который позволит задать всех пользователей, которые имеют отношение к классу, к которому применяется атрибут.
Для задания атрибуты, нужно создать класс, унаследованный от System.Attribure имя класса, желательно, должно быть в виде NameAtrtribure, хотя использование суффикса Attribute не обязательно, но соответствует стандарту именования.
internal class AuthorNameAttribute : Attribute
{
private readonly String _name;
public AuthorNameAttribute(string name)
{
_name = name;
}
public String Name
{
get { return _name; }
}
}
Чтобы ограничить область действия нашего атрибута, необходимо воспользоваться атрибутом [AttributeUsage]. Область действия задаётся любой комбинацией из перечисления AttributeTargets, посредством операции OR. По умолчанию равен AttributeTargets.All.
Значения AttributeTargets:
public enum AttributeTargets
{
Assembly = 0x0001,
Module = 0x0002,
Class = 0x0004,
Struct = 0x0008,
Enum = 0x0010,
Constructor = 0x0020,
Method = 0x0040,
Property = 0x0080,
Field = 0x0100,
Event = 0x0200,
Interface = 0x0400,
Parameter = 0x0800,
Delegate = 0x1000,
ReturnValue = 0x2000,
GenericParameter = 0x4000,
All = Assembly | Module | Class | Struct | Enum | Constructor |
Method | Property | Field | Event | Interface | Parameter |
Delegate | ReturnValue | GenericParameter,
}
Помимо области действия еще можно задать 2 параметра, AllowMultiple и Inherited.
AllowMultiple — указывает, что атрибут можно применять несколько раз, по умолчанию равен false.
Inherited — указывает, будет ли атрибут, применяемый к базовому классу, применяться также к производным классам, по умолчанию равен true.
Для нашего атрибута установим область действия только для класса и укажем, что он может применяться несколько раз.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
internal class AuthorNameAttribute : Attribute
{
private readonly String _name;
public AuthorNameAttribute(string name)
{
_name = name;
}
public String Name
{
get { return _name; }
}
}
Теперь создадим класс MyProgram и определим функцию, которая будет выводить в консоль всех авторов данного класса.
[AuthorName("Василий Пупкин")]
[AuthorName("Дмитрий Иванов")]
public static class MyProgram
{
public static void PrintAuthors()
{
var thisType = typeof (MyProgram);
if (thisType.IsDefined(typeof (AuthorNameAttribute), false))
{
var authors = thisType.GetCustomAttributes(typeof(AuthorNameAttribute), false);
foreach (var author in authors)
{
var z = (AuthorNameAttribute) author;
Console.WriteLine(z.Name);
}
}
}
}
К классу MyProgram мы применили 2 атрибута AuthorName с пользователями Василий и Дмитрий. Метод PrintAuthors работает следующим образом:
var thisType = typeof (MyProgram); — Получает объект Type для класса MyProgram.
thisType.IsDefined(typeof (AuthorNameAttribute), false) — проверяет наличие хотябы одного экземпляра атрибута AuthorNameAttribute.
var authors = thisType.GetCustomAttributes(typeof(AuthorNameAttribute), false); - получает все атрибуты с типом AuthorNameAttribute.
foreach (var author in authors)
{
var z = (AuthorNameAttribute) author;
Console.WriteLine(z.Name);
}
Перебираем все атрибуты и выводим значение свойства Name в консоль.
Результат работы MyProgram.PrintAuthors(); будут следующий:
GetCustomAttributes — возвращает массив, каждый элемент которого является экземпляром указанного класса атрибута.
GetCustomAttribute — возвращает экземпляр указанного класса атрибута.p>
IsDefined — возвращает значение true при наличии хотя бы одного экземпляра указанного класса, производного от Attribute, связанного с целью.
Также нужно помнить, что .NET позволяет не только создавать собственные атрибуты с нуля, но и создавать новые, на основе уже имеющихся.