Чтение онлайн

на главную - закладки

Жанры

Полное руководство. С# 4.0
Шрифт:

Рассмотрим следующий пример, демонстрирующий полностью автоматизирован ное обнаружение типов. В этом примере сначала загружается сборка MyClasses.ехе, затем конструируется объект класса MyClass и далее вызываются все методы, объяв ленные в классе MyClass, причем о них ничего заранее неизвестно. // Использовать класс MyClass, ничего не зная о нем заранее. using System; using System.Reflection; class ReflectAssemblyDemo { static void Main { int val; Assembly asm = Assembly.LoadFrom("MyClasses.exe"); Type[] alltypes = asm.GetTypes; Type t = alltypes[0]; // использовать первый обнаруженный класс Console.WriteLine("Использовано: " + t.Name); ConstructorInfo[] ci = t.GetConstructors; // Использовать первый обнаруженный конструктор. ParameterInfо[] cpi = ci[0].GetParameters; object reflectOb; if(cpi.Length > 0) { object[] consargs = new object[cpi.Length]; //

Инициализировать аргументы. fox(int n=0; n < cpi.Length; n++) consargs[n] = 10 + n * 20; // Сконструировать объект. reflectOb = ci[0].Invoke(consargs); } else reflectOb = ci[0].Invoke(null); Console.WriteLine("\nВызов методов для объекта reflectOb."); Console.WriteLine; // Игнорировать наследуемые методы. MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); // Вызвать каждый метод. foreach(Methodlnfo m in mi) { Console.WriteLine("Вызов метода {0} ", m.Name); // Получить параметры. ParameterInfo[] pi = m.GetParameters; // Выполнить методы. switch(pi.Length) { case 0: // аргументы отсутствуют if(m.ReturnType == typeof(int)) { val = (int) m.Invoke(reflectOb, null); Console.WriteLine("Результат: " + val); } else if(m.ReturnType == typeof(void)) { m.Invoke(reflectOb, null); } break; case 1: // один аргумент if(pi[0].ParameterType == typeof(int)) { object[] args = new object[1]; args[0] = 14; if((bool) m.Invoke(reflectOb, args)) Console.WriteLine("Значение 14 находится между x и у"); else Console.WriteLine("Значение 14 не находится между х и у"); } break; case 2: // два аргумента if((pi[0].ParameterType == typeof(int)) && (pi[1].ParameterType == typeof (int))) { object[] args = new object[2]; args[0] = 9; args[1] = 18; m.Invoke(reflectOb, args); } else if((pi[0].ParameterType == typeof(double)) && (pi[1].ParameterType == typeof(double))) { object[] args = new object[2]; args[0] = 1.12; args[1] = 23.4; m.Invoke(reflectOb, args); } break; } Console.WriteLine; } } }

Эта программа дает следующий результат. Использовано: MyClass Конструирование класса MyClass(int). Значение х: 10, значение у: 10 Вызов методов для объекта reflectOb. Вызов метода Sum Результат: 20 Вызов метода IsBetween Значение 14 не находится между х и у Вызов метода Set В методе Set(int, int). Значение х: 9, значение у: 18 Вызов метода Set В методе Set(double, double). Значение х: 1, значение у: 23 Вызов метода Show Значение х: 1, значение у: 23

Эта программа работает довольно просто, но все же требует некоторых пояснений. Во-первых, получаются и используются только те методы, которые явно объявлены в классе MyClass. Для этой цели служит форма BindingFlags метода GetMethods, чтобы воспрепятствовать вызову методов, наследуемых от объекта. И во-вторых, ко личество параметров и возвращаемый тип каждого метода получаются динамически, а затем определяются и проверяются в операторе switch. На основании этой инфор мации формируется вызов каждого метода. Атрибуты

В C# разрешается вводить в программу информацию декларативного характера в форме атрибута, с помощью которого определяются дополнительные сведения (метаданные), связанные с классом, структурой, методом и т.д. Например, в програм ме можно указать атрибут, определяющий тип кнопки, которую должен отображать конкретный класс. Атрибуты указываются в квадратных скобках перед тем элементом, к которому они применяются. Следовательно, атрибут не является членом класса, но обозначает дополнительную информацию, присоединяемую к элементу. Основы применения атрибутов

Атрибут поддерживается классом, наследующим от класса System.Attribute. Поэтому классы атрибутов должны быть подклассами класса Attribute. В классе Attribute определены основные функциональные возможности, но далеко не все они нужны для работы с атрибутами. В именах классов атрибутов принято употреблять суффикс Attribute. Например, ErrorAttribute — это имя класса атрибута, опи сывающего ошибку.

При объявлении класса атрибута перед его именем указывается атрибут AttributeUsage. Этот встроенный атрибут обозначает типы элементов, к которым может применяться объявляемый атрибут. Так, применение атрибута может ограни чиваться одними методами. Создание атрибута

В классе атрибута определяются члены, поддерживающие атрибут. Классы

атри бутов зачастую оказываются довольно простыми и содержат небольшое количество полей или свойств. Например, атрибут может определять примечание, описывающее элемент, к которому присоединяется атрибут. Такой атрибут может принимать сле дующий вид. [AttributeUsage(AttributeTargets.All)] public class RemarkAttribute : Attribute { string pri_remark; // базовое поле свойства Remark public RemarkAttribute(string comment) { pri_remark = comment; } public string Remark { get { return pri_remark; } } }

Проанализируем этот класс атрибута построчно.

Объявляемый атрибут получает имя RemarkAttribute. Его объявлению пред шествует встроенный атрибут AttributeUsage, указывающий на то, что атрибут RemarkAttribute может применяться ко всем типам элементов. С помощью встроен ного атрибута AttributeUsage можно сузить перечень элементов, к которым может присоединяться объявляемый атрибут. Подробнее о его возможностях речь пойдет далее в этой главе.

Далее объявляется класс RemarkAttribute, наследующий от класса Attribute. В классе RemarkAttribute определяется единственное закрытое поле pri_remark, поддерживающее одно открытое и доступное для чтения свойство Remark. Это свой ство содержит описание, связываемое с атрибутом. (Конечно, Remark можно было бы объявить как автоматически реализуемое свойство с закрытым аксессором set, но ради наглядности данного примера выбрано свойство, доступное только для чтения.) В данном классе определен также один открытый конструктор, принимающий стро ковый аргумент и присваивающий его свойству Remark. Этим пока что ограничивают ся функциональные возможности класса RemarkAttribute, готового к применению. Присоединение атрибута

Как только класс атрибута будет определен, атрибут можно присоединить к эле менту. Атрибут указывается перед тем элементом, к которому он присоединяется, и для этого его конструктор заключается в квадратные скобки. В качестве примера ниже показано, как атрибут RemarkAttribute связывается с классом. [RemarkAttribute("В этом классе используется атрибут.")] class UseAttrib { // ... }

В этом фрагменте кода конструируется атрибут RemarkAttribute, содержащий комментарий "В этом классе используется атрибут." Данный атрибут затем связывается с классом UseAttrib.

Присоединяя атрибут, совсем не обязательно указывать суффикс Attribute. Например, приведенный выше класс может быть объявлен следующим образом. [Remark("В этом классе используется атрибут.")] class UseAttrib { // ... }

В этом объявлении указывается только имя Remark. Такая сокращенная форма счи тается вполне допустимой, но все же надежнее указывать полное имя присоединяемо го атрибута, чтобы избежать возможной путаницы и неоднозначности. Получение атрибутов объекта

Как только атрибут будет присоединен к элементу, он может быть извлечен в дру гих частях программы. Для извлечения атрибута обычно используется один из двух методов. Первый метод, GetCustomAttributes, определяется в классе MemberInfо и наследуется классом Туре. Он извлекает список всех атрибутов, присоединенных к элементу. Ниже приведена одна из его форм. object[] GetCustomAttributes(bool наследование)

Если наследование имеет логическое значение true, то в список включаются атрибуты всех базовых классов, наследуемых по иерархической цепочке. В противном случае атрибуты извлекаются только из тех классов, которые определяются указанным типом.

Второй метод, GetCustomAttribute, определяется в классе Attribute. Ниже приведена одна из его форм: static Attribute GetCustomAttribute(MemberInfo элемент, Type тип_атрибута)

где элемент обозначает объект класса MemberInfo, описывающий тот элемент, для ко торого создаются атрибуты, тогда как тип_атрибута — требуемый атрибут. Данный метод используется в том случае, если имя получаемого атрибута известно заранее, что зачастую и бывает. Так, если в классе UseAttrib имеется атрибут RemarkAttribute, то для получения ссылки на этот атрибут можно воспользоваться следующей после довательностью кода. // Получить экземпляр объекта класса MemberInfо, связанного // с классом, содержащим атрибут RemarkAttribute. Type t = typeof(UseAttrib); // Извлечь атрибут RemarkAttribute. Type tRemAtt = typeof(RemarkAttribute); RemarkAttribute ra = (RemarkAttribute) Attribute.GetCustomAttribute(t, tRemAtt);

Поделиться:
Популярные книги

Идеальный мир для Лекаря 11

Сапфир Олег
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 11

Обгоняя время

Иванов Дмитрий
13. Девяностые
Фантастика:
попаданцы
5.00
рейтинг книги
Обгоняя время

Я все еще граф. Книга IX

Дрейк Сириус
9. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я все еще граф. Книга IX

Идеальный мир для Лекаря

Сапфир Олег
1. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря

Мастер 4

Чащин Валерий
4. Мастер
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Мастер 4

Элита элит

Злотников Роман Валерьевич
1. Элита элит
Фантастика:
боевая фантастика
8.93
рейтинг книги
Элита элит

Ненаглядная жена его светлости

Зика Натаэль
Любовные романы:
любовно-фантастические романы
6.23
рейтинг книги
Ненаглядная жена его светлости

Золушка вне правил

Шах Ольга
Любовные романы:
любовно-фантастические романы
6.83
рейтинг книги
Золушка вне правил

Вперед в прошлое 2

Ратманов Денис
2. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 2

Сердце Дракона. Том 10

Клеванский Кирилл Сергеевич
10. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.14
рейтинг книги
Сердце Дракона. Том 10

Жребий некроманта 2

Решетов Евгений Валерьевич
2. Жребий некроманта
Фантастика:
боевая фантастика
6.87
рейтинг книги
Жребий некроманта 2

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Хорошая девочка

Кистяева Марина
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Хорошая девочка

Эволюционер из трущоб. Том 4

Панарин Антон
4. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 4