ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
Идея аннотирования программного кода с помощью атрибутов не нова. Множество встроенных атрибутов предлагает COM IDL (Interface Definition Language – язык описания интерфейсов), что позволяет разработчику описывать типы COM-сервера. Однако атрибуты COM представляют собой, по сути, лишь набор ключевых слов. Если перед разработчиком COM возникает задача создания пользовательских атрибутов, то эта задача оказывается вполне разрешимой, но ссылаться на такой атрибут в программном коде придется с помощью 128-разрядного номера (GUID), а это, в лучшем случае, слишком обременительно.
В отличие от атрибутов COM IDL (которые, напомним, являются просто ключевыми словами), атрибуты .NET являются типами класса, расширяющими абстрактный базовый класс System.Attribute. При исследовании пространств имен .NET вы можете обнаружить множество встроенных атрибутов, которые можно использовать в приложениях. К тому же вы можете строить свои пользовательские атрибуты, чтобы затем корректировать поведение своих типов с помощью создания новых типов, производных от Attribute.
Следует понимать, что при использовании атрибутов в программном коде вложенные вами метаданные остаются, по сути, бесполезными до тех пор, пока другой фрагмент программного кода не использует явно отображение соответствующей информации. До этого метаданные, вложенные вами в компоновочный блок, просто игнорируются.
Потребители атрибутов
Как вы можете догадаться, в комплекте с .NET Framework 2.0 SDK поставляется множество утилит, предназначенных для работы с различными атрибутами. Даже компилятор C# (csc.exe) запрограммирован на проверку определенных атрибутов в процессе компиляции. Например, если компилятор C# обнаруживает атрибут [CLSCompilant], он автоматически проверяет соответствующий элемент на совместимость всех его конструкций с CLS. Если же компилятор C# обнаружит элемент с атрибутом [Obsolete], в окне сообщений об ошибках Visual Studio 2005 появится соответствующее предупреждение.
Вдобавок к инструментам разработки, многие методы из библиотек базовых классов .NET тоже запрограммированы на работу с конкретными атрибутами. Например, если вы хотите сохранить состояние объекта в файле, необходимо указать для класса атрибут [Serializable]. Когда метод Serialize() класса BinaryFormatter обнаруживает указанное свойство, объект автоматически сохраняется в файл в компактном двоичном формате.
Среда CLR также контролирует наличие определенных атрибутов. Возможно, самым известным из атрибутов .NET является [WebMethod]. Если вы хотите открыть метод для запросов HTTP и автоматически кодировать возвращаемое значение метода в формат XML, просто укажите атрибут [WebMethod] для этого метода, и всю рутинную работу среда CLR выполнит сама. Кроме разработки Web-сервисов, атрибуты важны дли системы безопасности .NET, слоя операций удаленного доступа, взаимодействия COM/.NET и т.д.
Наконец, можно строить приложения, которые, наряду с атрибутами библиотек базовых классов .NET. будут отображать пользовательские атрибуты. Такой подход позволяет создавать наборы "ключевых слов", понятных только заданному множеству компоновочных блоков.
Применение встроенных атрибутов C#
Как упоминалось выше, библиотека базовых классов .NET предлагает целый ряд атрибутов из разных пространств имен. В табл. 12.3 приводится короткий список некоторых из таких атрибутов (и, конечно же, далеко не всех).
Чтобы привести пример применения атрибутов в C#, предположим, что нам нужно построить класс Motorcycle (мотоцикл), допускающий сериализацию в двоичном формате. Для этого мы должны просто добавить атрибут [Serializable] в определение класса. Если при этом какое-то поле при сериализации сохраняться не должно, то к нему можно применить атрибут [NonSerialized].
// Этот класс можно сохранить на диске.
[Serializable]
public class Motorcycle {
// Но это поле сохраняться не должно.
[NonSerialized]
float weightOfCurrentPassengers;
// Следующие поля сохраняются.
bool hasRadioSystem;
bool hasHeadSet;
bool hasSissyBar;
}
Таблица 12.3. Малая часть встроенных атрибутов
Атрибут Описание [CLSCompliant] Требует от элемента строгого соответствия правилам CLS (Common Language Specification – общеязыковые спецификации). Напомним, что соответствующие CLS-спецификациям типы гарантированно могут использоваться во всех языках программирования .NET [DllImport] Позволяет программному коду .NET вызывать библиотеки программного кода C или C++ (которые не являются управляемыми), включая API (Application Programming Interface – программный интерфейс приложения) операционной системы. Заметьте, что [DllImport] не используется при взаимодействии с программным обеспечением COM [Obsolete] Обозначает устаревший тип или член. При попытке использовать такой элемент программист получит предупреждение компилятора с соответствующим описанием ошибки [Serializable] Обозначает возможность сериализации класса или структуры [NonSerialized] Указывает, что данное поле класса или структуры не должно сохраняться в процессе сериализации [WebMethod] Обозначает доступность метода для вызова через запросы HTTP и требует от среды CLR сохранения возвращаемого значения метода в формате XML (подробности можно найти в главе 25)Замечание. Указанный атрибут применяется только к элементу, непосредственно следующему за атрибутом. Например, единственным не сохраняемым полем класса Motorcycle будет weightOfCurrentPassengers. Остальные поля при сериализации сохраняются, поскольку весь класс аннотирован атрибутом [Serializable].
Пока что не беспокойтесь о сути самого процесса сериализации объекта (подробности этого процесса будут рассмотрены в главе 17). Обратите внимание только на то, что при использовании атрибута его имя должно заключаться в квадратные скобки.
После компиляции этого класса можете проверить его метаданные с помощью ildasm.exe. Соответствующие атрибуты будут обозначены метками serializable и notserialized (рис. 12.6).
Как вы можете догадаться сами, один элемент может иметь много атрибутов. Предположим, что у нас есть тип класса C# (HorseAndBuggy), обозначенный как serializable, но теперь он считается устаревшим.
Рис. 12.6. Отображение атрибутов в окне ildasm.exe
Чтобы применить множество атрибутов к одному элементу, используйте список значений, разделенных запятыми.
[Serializable,
Obsolete("Класс устарел, используйте другой транспорт!")]
public class HorseAndBuggy {
// …
}
В качестве альтернативы, чтобы применить несколько атрибутов к одному элементу, можно просто указать их по порядку (результат будет тем же).
[Serializable]
[Obsolete("Класс устарел, используйте другой транспорт!")]
public class HorseAndBuggy {
// …
}
Параметры конструктора для атрибутов
Мы видим, что атрибут [Obsolete] может принимать нечто похожее на параметр конструктора. Если вы посмотрите на формальное определение атрибута [Obsolete] в окне определения программного кода Visual Studio 2005, то увидите, что данный класс действительно предлагает конструктор, получающий System.String.
public sealed сlass ObsoleteAttribute: System.Attribute {
public bool IsError { get; }
public string Message { get; }
public ObsoleteAttribute(string message, bool error);
public ObsoleteAttribute(string message);
public ObsoleteAttribute();
}
Когда вы указываете параметры конструктора для атрибута, атрибут не размещается в памяти до тех пор, пока эти параметры не отобразятся другим типом или внешним программным средством. Строки, определенные на уровне атрибута, просто запоминаются в компоновочном блоке, как часть метаданных.
Атрибут Obsolete в действии
Теперь, когда класс HorseAndBuggy обозначен как устаревший, при размещении экземпляра этого типа вы должны увидеть соответствующую строку в сообщении, появившемся в окне со списком ошибок Visual Studio 2005 (рис. 12.7).
Рис. 12.7. Атрибуты в действии
В данном случае "другим фрагментом программного обеспечения", отображающим атрибут [Obsolete], является компилятор C#.
Сокращенное представление атрибутов в C#
При внимательном изучении материала этой главы вы могли заметить, что фактическим именем класса атрибута [Obsolete] является не Obsolete, a ObsoleteAttribute. По соглашению для имен все атрибуты .NET (и пользовательские атрибуты в том числе) должны в конце имени получить суффикс Attribute. Однако, чтобы упростить процедуру применения атрибутов, в языке C# не требуется, чтобы вы обязательно добавляли этот суффикс. Поэтому следующий вариант определения типа HorseAndBuggy будет идентичен предыдущему (при этом только потребуется ввести немного больше символов).