Определение класса атрибута. Определение базового класса.
Чтобы создать пользовательский атрибут, необходимо определить класс атрибута, производный от базового класса Attribute (Атрибут). В соответствии с соглашением, нужно дать классу имя, заканчивающееся на "Attribute" ("Атрибут"). Имя класса без суффикса "Attribute" ("Атрибут") будет названием пользовательского атрибута. В нашем примере имя класса – InitialDirectoryAttribute, поэтому название атрибута – Initial-Directory.
Можно реализовать один или несколько конструкторов для класса атрибута. Конструкторы определяют, как передать позиционные параметры для атрибута (предоставив список параметров, разделенных запятыми). Возможно также предусмотреть "поименованные параметры" для пользовательского атрибута, чтобы при передаче информации через параметр можно было использовать синтаксис имя=значение.
Можно также предусмотреть свойства для чтения информации, передаваемой через параметр. В нашем примере есть свойство Path (Путь), которое инициализируется в конструкторе.
//DirectoryAttribute.h using namespace System; // использование пространства имен Система; public _gc class InitialDirectoryAttribute: // класс сборщика мусора InitialDirectoryAttribute: public Attribute // общедоступный Атрибут { private: // частный String *path; // Строка public: InitialDirectoryAttribute(String *path) // Строка { this › path = path; // путь }' _property String *get_Path() // Строка свойства { return path; // путь } };
Определение базового класса
Последний шаг при работе с самостоятельно создаваемыми атрибутами состоит в том, чтобы предусмотреть способ извлечения пользовательской информации об атрибуте из метаданных при помощи классов отражения. Можно получить Type (Тип) любого объекта, вызывая метод GetType, который предоставляется корневым классом Object (Объект). Метод GetCustomAttributes этого класса позволяет прочитать пользовательскую информацию об атрибуте.
Чтобы упростить создание клиентской программы, часто полезно создать базовый класс, который будет проделывать работу по чтению пользовательской информации об атрибутах. Мы создадим базовый класс DirectoryContext, который будет использоваться классом, желающим воспользоваться преимуществом атрибута Initial-Directory. Этот базовый класс предоставляет свойство DirectoryPath, чтобы возвратить информацию о пути, хранящуюся в метаданных. Вот листинг базового класса:
//DirectoryContext.h using namespace System; // использование пространства имен Система; using namespace System::Reflection; // использование пространства имен Система::Отражение; using namespace System::10; // использование пространства имен Система::10; using namespace System:Collections; использование пространства имен Система::Коллекции; _gc class DirectoryContext // класс сборщика мусора DirectoryContext { public: _property String *get_DirectoryPath() // Строка свойства { Type *t = this › GetType(); lEnumerator *pEnum = t › GetCustomAttributes(true) › GetEnumerator(); while (pEnum › MoveNext()) { Attribute *a = dynamic_cast<Attribute *>(pEnum › Current); // Атрибут InitialDirectoryAttribute *da = dynamic_cast<InitialDirectoryAttribute *>(a); if (da!= 0) // если (da! = 0) { return da › Path; // Путь } } return Directory::GetCurrentDirectory(); // Каталог } };
Создав базовый класс, можно столкнуться с трудностями, если допускается только единичное наследование реализации. Если класс должен быть производным от другого класса, например ContextBoundObject, то ваш базовый класс должен быть производным от этого класса.
Нужно импортировать пространство имен System::Reflection (Система-Отражение). GetType возвращает текущий объект Type (Тип), и тогда можно использовать метод GetCustomAttributes, чтобы получить коллекцию объектов Attribute (Атрибут) из метаданных. Так как эта коллекция неоднородна, поскольку состоит из различных типов, используется оператор dynamic_cast, чтобы проверить, принадлежит ли данный элемент коллекции к типу InitialDirectoryAttribute. Если такой элемент найдется, возвращается свойство Path (Путь). В противном случае возвращается заданный по умолчанию текущий каталог, который можно получить из GetCurrentDirectory.