Когда вы указываете параметры конструктора для атрибута, атрибут не размещается в памяти до тех пор, пока эти параметры не отобразятся другим типом или внешним программным средством. Строки, определенные на уровне атрибута, просто запоминаются в компоновочном блоке, как часть метаданных.
Атрибут Obsolete в действии
Теперь, когда класс HorseAndBuggy обозначен как устаревший, при размещении экземпляра этого типа вы должны увидеть соответствующую строку в сообщении, появившемся в окне со списком ошибок Visual Studio 2005 (рис. 12.7).
Рис. 12.7. Атрибуты в действии
В данном случае "другим фрагментом программного обеспечения", отображающим атрибут [Obsolete], является компилятор C#.
Сокращенное представление атрибутов в 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 {
//…
}