Г. Шилдт - Полный справочник по C# (1160789), страница 86
Текст из файла (страница 86)
В реальных приложениях необходимо проверять тип каждогоаргумента.Получение типов из компоновочных файловВ предыдущем примере с помощью средства отражения мы многое узнали о классеMyClass, но не все: мы не получили данные о самом типе MyClass. Несмотря на точто мы динамически извлекли из соответствующих объектов информацию о типеMyClass, мы исходили из того, что нам заранее было известно имя типа MyClass, ииспользовали инструкцию typeof для получения объекта класса Туре, для котороговызывались все методы средства отражения (напрямую или опосредованно).
И хотя внекоторых ситуациях такой подход себя вполне оправдывает, возможности средстваотражения проявляются в полной мере тогда, когда программа в состоянии определить необходимые типы посредством анализа содержимого других компоновчныхфайлов.Как было описано в главе 16, компоновочный файл включает информацию о классах, структурах и пр., которые он содержит. Интерфейс Reflection API позволяет загрузить компоновочный файл, извлечь информацию о нем и создать экземпляры любого из содержащихся в нем типов.
Используя этот механизм, программа может проанализировать среду выполнения и заставить ее поработать в нужном направлении, неопределяя явным образом "точки приложения" во время компиляции. Это чрезвычайно эффективное средство. Например, представьте себе программу, которая действует как броузер типов, отображая доступные в системе типы. Или представьте другоеприложение, которое выполняло бы роль средства проектирования, позволяющего визуально связывать отдельные части программы, состоящей из различных типов, поддерживаемых системой. Если все данные о типе поддаются обнаружению, то не существует ограничений на применение средства отражения.Для получения информации о компоновочном файле сначала необходимо создатьобъект класса Assembly.
Класс Assembly не определяет ни одного p u b l i c конструктора. Но объект класса Assembly можно создать, вызвав один из его методов.Например, воспользуемся методом LoadFromO . Вот формат его использования:s t a t i c Assembly LoadFrom(string имя_файла)Здесь элемент имя_файла означает имя компоновочного файла.Создав объект класса Assembly, можно получить содержащуюся в нем информацию о типах с помощью метода GetTypes ().
Формат его вызова таков:Туре[] GetTypes()Этот метод возвращает массив типов, содержащихся в компоновочном файле.Чтобы продемонстрировать получение информации о типах из компоновочногофайла, нужно иметь два файла. Первый должен включать набор классов. Поэтомусоздадим файл MyClasses.cs с таким содержимым:I // Этот файл содержит три класса.| // Назовите его MyClasses.cs.466Часть I. Язык С#using System;class MyClass {int x;int y;public MyClass(int i) {Console.WriteLine("Создание объекта по формату MyClass(int).x = у = i;show();public MyClass(int i, int j) {Console.WriteLine("Создание объекта по формату MyClass(int, int).
")x = i;у = j;show();public int sum() {return x+y;public bool isBetween(int i) {if((x < i) && (i < y)) return true;else return false;public void set(int a, int b) {Console.Write("Внутри метода set(int, int). " ) ;x = a;у = b;show () ;// Перегруженный метод set.public void set(double a, double b) {Console.Write("Внутри метода set(double, double). " ) ;x = (int) a;у = (int) b;show();public void show() {Console.WriteLine("Значение х: {0}, значение у: {1}", x, у ) ;class AnotherClass {string remark;public AnotherClass(string str) {remark = str;Глава 17.
Динамическая идентификация типов, отражение и атрибуты467public void show() {Console.WriteLine(remark);class Demo {public static void Main() {Console.WriteLine("Это заглушка.");Этот файл содержит класс MyClass, который мы использовали в предыдущихпримерах. Кроме того, сюда входит класс AnotherClass и еще один класс — Demo.Таким образом, компоновочный файл, генерируемый программой, должен содержатьтри класса. Теперь скомпилируем этот файл, чтобы получить файл MyClasses.exe.Это и есть компоновочный файл, который мы будем опрашивать.Теперь рассмотрим программу, которая извлекает информацию о файле^lyClasses.exe./* Находим компоновочный файл, определяем типы исоздаем объект, используя средство отражения.
*/using System;using System.Reflection;class ReflectAssemblyDemo {public static void Main() {int val;// Загружаем компоновочный файл MyClasses.exe.Assembly asm = Assembly.LoadFrom("MyClasses.exe");// Узнаем, какие типы содержит файл MyClasses.exe.Туре[] alltypes = asm.GetTypes();foreach(Type temp in alltypes)Console.WriteLine("Обнаружено: " + temp.Name);Console.WriteLine();// Используем первый тип,// которым в данном случае является MyClass.Type t = alltypes[0]; // Анализируем первый// обнаруженный класс.Console.WriteLine("Используем: " + t.Name);// Получаем информацию о конструкторах.Constructorlnfo[] ci = t.GetConstructors();Console.WriteLine("Имеются следующие конструкторы: " ) ;foreach(Constructorlnfo с in ci) {// Отображаем тип возвращаемого значения и имя.Console.Write("" + t.Name + " ( " ) ;// Отображаем параметры.Parameterlnfo[] pi = c.GetParameters();for(int i=0; i < pi.Length; i++) {Console.Write(pi[i].ParameterType.Name +468Часть I.
Язык С#" " + pi[i].Name);if(i + l < pi.Length) Console.Write(", ") ;}Console.WriteLine(")");}Console.WriteLine() ;// Находим подходящий конструктор,int x;for(x=0; x < ci.Length; x++) {Parameterlnfo[] pi = ci[x].GetParameters();if(pi.Length == 2) break;}if(x == ci.Length) {Console.WriteLine("Подходящий конструктор не найден.");return;}elseConsole.WriteLine("Найден конструктор с двумя параметрами.\n") ;// Создаем объект.object[] consargs = new object[2];consargs[0] = 1 0 ;consargs[1] = 20;object reflectOb = ci[x].Invoke(consargs);Console.WriteLine("ХпВызов методов для объекта reflectOb.");Console.WriteLine();Methodlnfo[] mi = t.GetMethods();// Вызываем каждый метод.foreach(Methodlnfо m in mi) {// Получаем параметры.Parameterlnfo[] pi = m.GetParameters();if(m.Name.CompareTo("set")==0 &&pi[0].ParameterType == typeof(int)) {// Это метод set(int, int).object[] args = new object[2];args[0] = 9;args[1] = 18;m.Invoke(reflectOb, args);}else if(m.Name.CompareTo("set")==0 &&pi[0].ParameterType == typeof(double)) {// Это метод set(double, double).object[] args = new object[2];args[0] = 1.12;args[l] = 23.4;m.Invoke(reflectOb, args);}else if(m.Name.CompareTo("sum")==0) {Глава 17.
Динамическая идентификация типов, отражение и атрибуты469val = (int) m.Invoke(reflectOb, null);Console.WriteLine("Результат выполнения метода sum() равен " +val) ;}else if(m.Name.CompareTo("isBetween")==0) {object[] args = new object[1];args[0] = 14;if((bool) m.Invoke(reflectOb, args))Console.WriteLine("14 находится между х и у . " ) ;}else if(m.Name.CompareTo("show")==0) {m.Invoke(reflectOb, null);Результаты выполнения этой программы таковы:Обнаружено: MyClassОбнаружено: AnotherClassОбнаружено: DemoИспользуем: MyClassИмеются следующие конструкторы:MyClass(Int32 i)MyClass(Int32 i, Int32 j)'Найден конструктор с двумя параметрами.Создание объекта по формату MyClass(int, int).Значение х: 10, значение у: 20Вызов методов для объекта reflectOb.Результат выполнения метода sum() равен 3014 находится между х и у.Внутри метода set(int, int). Значение х: 9, значение у: 18Внутри метода set(double, double). Значение х: 1, значение у: 23Значение х: 1, значение у: 23Как видно из результатов выполнения программы, были обнаружены все три класса, содержащиеся в файле MyClasses.exe.
Первый из выявленных классов, в данномслучае это MyClass, был использован для реализации объекта и выполнения его методов. Причем все это было проделано без использования информации о содержимомфайла MyClasses. ехе.Информация о типах, содержащихся в файле MyClasses.exe, извлекается с помощью следующей последовательности инструкций, которыми открывается методMain ():// Загружаем компоновочный файл MyClasses.exe.Assembly asm = Assembly.LoadFrom("MyClasses.exe");// Узнаем, какие типы содержит файл MyClasses.exe.Type[] alltypes = asm.GetTypes();foreach(Type temp in alltypes)Console.WriteLine("Обнаружено: " + temp.Name);470Часть I. Язык С #Эту последовательность инструкций можно использовать в случае, когда нужнодинамически загрузить и опросить компоновочный файл.Кстати, компоновочный файл необязательно должен быть ехе-файлом.