Рейтинговые книги
Читем онлайн ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 107 108 109 110 111 112 113 114 115 ... 259

Сокращенное представление атрибутов в C#

При внимательном изучении материала этой главы вы могли заметить, что фактическим именем класса атрибута [Obsolete] является не Obsolete, a ObsoleteAttribute. По соглашению для имен все атрибуты .NET (и пользовательские атрибуты в том числе) должны в конце имени получить суффикс Attribute. Однако, чтобы упростить процедуру применения атрибутов, в языке C# не требуется, чтобы вы обязательно добавляли этот суффикс. Поэтому следующий вариант определения типа HorseAndBuggy будет идентичен предыдущему (при этом только потребуется ввести немного больше символов).

[SerializableAttribute]

[ObsoleteAttribute("Класс устарел, используйте другой транспорт!")]

public class HorseAndBuggy {

 //…

}

Это упрощение предлагается самим языком C#, и следует подчеркнуть, что эту особенность поддерживают не все языки .NET. Так или иначе, к этому моменту нашего обсуждения вы должны понимать следующие основные особенности, касающиеся атрибутов .NET.

• Атрибуты являются классами, производными от System.Attribute.

• Информация атрибутов добавляется в метаданные.

• Атрибуты будут бесполезны до тех пор, пока другой агент не отобразит их.

• Атрибуты в C# применяются с использованием квадратных скобок.

Теперь мы рассмотрим то, как можно строить свои собственные пользовательские атрибуты и пользовательские программы, отображающие встроенные метаданные.

Создание пользовательских атрибутов

Первым шагом процесса построения пользовательского атрибута является создание нового класса, производного от System.Attribute. В продолжение автомобильной темы, используемой в этой книге, мы создадим новую библиотеку классов C# с именем AttributedCarLibrary. Соответствующий компоновочный блок определит группу транспортных средств (определения некоторых из них, мы уже увидели выше), и при их описании будет использован пользовательский атрибут VehiсleDescriptionAttribute,

// Пользовательский атрибут.

public sealed class VehicleDescriptionAttribute: System.Attribute {

 private string msgData;

 public VehicleDescriptionAttribute(string description) { msgData = description; }

 public VehicleDescriptionAttribute() {}

 public string Description {

  get { return msgData; }

  set { msgData = value; }

 }

}

Как видите, VehicleDescriptionAttribute поддерживает приватную внутреннюю строку (msgData), значение которой можно установить с помощью пользовательского конструктора, а изменять - с помощью свойства типа (Description). Кроме того, что этот класс является производным от System.Attribute, его определение ничем особенным больше не отличается,

Замечание. С точки зрения безопасности рекомендуется, чтобы все пользовательские атрибуты…NET создавались, как изолированные классы.

Применение пользовательских атрибутов

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

// Назначение описания с помощью 'именованного свойства'.

[Serializable,

VehicleDescription(Description = "Мой сияющий Харлей")]

public class Motorcycle {

 //…

}

[SerializableAttribute]

[ObsoleteAttribute("Класс устарел, используйте другой транспорт!"), VehicleDescription("Старая серая кляча, она уже совсем не та…")]

public class HorseAndBuggy {

 //…

}

[VehicleDescription("Большое, тяжелое, но высокотехнологичное авто"

public class Winnebago {

 //…

}

Обратите внимание на то, что описание класса Motorcycle здесь указано с помощью нового элемента синтаксиса, называемого именованным свойством. В конструкторе первого атрибута [VehicleDescription] соответствующее значение System.String устанавливается с помощью пары "имя-значение". При отображении этого атрибута внешним агентом соответствующее значение передается свойству Description (синтаксис именованного свойства здесь корректен только в том случае, когда атрибут предлагает перезаписываемое свойство .NET). В противоположность этому типы HorseAndBuggy и Winnebago не используют синтаксис именованного свойства, а просто передают строковые данные в пользовательский конструктор.

После компиляции компоновочного блока AttributedCarLibrary можно использовать ildasm.exe, чтобы увидеть метаданные с описанием добавленного типа. Так, на рис. 12.8 показано встроенное описание типа Winnebago.

Рис. 12.8. Встроенные данные описания транспортного средства

Ограничение использования атрибута

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

[VehicleDescription("Большое, тяжелое, но высокотехнологичное авто")]

public class Winnebago {

 [VehicleDescription("Мой мощный CD-плейер")]

 public void PlayMusic(bool On) {

  …

 }

}

В некоторых случаях это оказывается именно тем, что нужно. Но в других случаях бывает нужно создать пользовательский атрибут, который должен применяться только к определенным элементам программного кода. Если вы хотите ограничить контекст применения пользовательского атрибута, то при определении пользовательского атрибута нужна применить атрибут [AttributeUsage]. Атрибут [AttributeUsage] позволяет указать любую комбинацию значений (связанных операцией OR) из перечня AttributeTargets.

// Этот перечень задает возможные целевые значения для атрибута.

public enum AttributeTargets {

 All, Assembly, Class, Constructor,

 Delegate, Enum, Event, Field,

 Interface, Method, Module, Parameter,

 Property, ReturnValue, Struct

}

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

Чтобы атрибут [VehicleDescription] мог применяться к классу или структуре только один раз (и соответствующее значение не наследовалось производными типами), можно изменить определение VehicleDescriptionAttribute так.

// На этот раз для аннотации нашего пользовательского атрибута

// мы используем атрибут AttributeUsage.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]

public class VehicleDescriptionAttribute: System.Attribute {

 …

}

Теперь если разработчик попытается применить атрибут [VehicleDescription] к чему-либо, кроме класса или структуры, будет сгенерировано сообщение об ошибке компиляции.

Совет. Вашей привычкой должно стать явное указание флагов применения для любого создаваемого вами пользовательского атрибута, поскольку не все языки программирования .NET приветствуют использование атрибутов, не имеющих квалификационных указаний!

Атрибуты уровня компоновочного блока (и уровня модуля)

Можно также задать применение атрибутов ко всем типам в рамках данного модуля или всех модулей в рамках данного компоновочного блока, если, соответственно, использовать признаки [module:] или [assembly:]. Предположим, что нам нужно гарантировать, чтобы каждый открытый тип, определенный в нашем компоновочном блоке, был CLS-допустимым. Для этого в любой из файлов исходного кода C# нужно добавить следующую строку (заметьте, что атрибуты уровня компоновочного блока должны быть указаны за пределами контекста определения пространства имен).

// Требование CLS-совместимости для всех открытых типов

// в данном компоновочном блоке.

[assembly:System.CLSCompliantAttribute(true)]

Если теперь добавить фрагмент программного кода, который выходит за пределы спецификации CLS (например, элемент данных без знака)

// Типы ulong не согласуется с CLS.

public class Winnebago {

 public ulong notCompliant;

}

то будет сгенерирована ошибка компиляции.

Файл AssemblyInfo.cs в Visual Studio 2005

По умолчанию Visual Studio 2005 генерирует файл с именем AssemblyInfo.cs (рис. 12.9).

Рис. 12.9. Файл AssemblyInfo.cs

Этот файл является удобным местом для хранения атрибутов, которые должны применяться на уровне компоновочного блока. В табл. 12.4 приводится список некоторых атрибутов уровня компоновочного блока, о которых вам следует знать.

Исходный код. Проект AttributedCarLibrary размещен в подкаталоге, соответствующем главе 12.

1 ... 107 108 109 110 111 112 113 114 115 ... 259
На этой странице вы можете бесплатно читать книгу ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен бесплатно.
Похожие на ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен книги

Оставить комментарий