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) {
val = (int) m.Invoke(reflectOb, null);
Console.WriteLine("Сумма равна " + 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 находится между x и у");
}
else ifjm.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
Сумма равна 30
Значение 14 находится между х и у
В методе Set (int, int) . Значение х: 9, значение у: 18 В методе Set(double, double). Значение х: 1, значение у: 23 Значение х: 1, значение у: 2 3
Как следует из результата выполнения приведенной выше программы, обнаружены все три класса, содержащиеся в файле сборки Му С lasses . ехе. Первым среди них обнаружен класс MyClass, который затем был использован для получения экземпляра объекта и вызова соответствующих методов.
Отдельные типы обнаруживаются в сборке MyClasses . ехе с помощью приведенной ниже последовательности кода, находящегося в самом начале методачМал.п ().
// Загрузить сборку MyClasses.exe.
Assembly asm = Assembly.LoadFrom("MyClasses.ехе") ;
// Обнаружить типы, содержащиеся в сборке MyClasses.exe.
Туре[] alltypes = asm.GetTypes(); foreach(Type temp in alltypes)
Console.WriteLine("Найдено: " + temp.Name);
Этой последовательностью кода можно пользоваться всякий раз, когда требуется динамически загружать й опрашивать сборку.
Но сборка совсем не обязательно должна быть исполняемым файлом с расширением . ехе. Сборки могут быть также в файлах динамически компонуемых библиотек (DLL) с расширением .dll. Так, если скомпилировать исходный файл MyClasses . cs в следующей командной строке:
csc /t:library MyClasses.es
То в итоге получится файл MyClasses .dll. Преимущество размещения кода в библиотеке DLL заключается, в частности, в том, что в этом случае метод Main () в исходном коде не нужен, тогда как всем исполняемым файлам требуется определенная точка входа, с которой должно начинаться выполнение программы. Именно поэтому класс Demo содержит метод Main () в качестве такой точки входа. А для библиотеки DLL метод Main () не требуется. Если же класс MyClass нужно превратить в библиотеку DLL, то в вызов метода LoadFrom () придется внести следующее изменение.
Assembly asm = Assembly.LoadFrom("MyClasses.dll");
Полностью автоматизированное обнаружение типов
Прежде чем завершить рассмотрение рефлексии, обратимся к еще одному поучительному примеру. Несмотря на то что в программе из предыдущего примера класс MyClass был полноценно использован без явного указания на его имя в программе, этот пример все же опирается на предварительную осведомленность о содержимом класса MyClass. Так, в программе были заранее известны имена методов Set и Sum из этого класса. Но с помощью рефлексии можно воспользоваться типом данных, ничего не зная о нем заранее. С этой целью придется извлечь все сведения, необходимые для конструирования объекта и формирования вызовов соответствующих методов. Такой подход может оказаться пригодным, например, при создании инструментального средства визуального проектирования, поскольку он позволяет использовать типы данных, имеющиеся в системе.
Рассмотрим следующий пример, демонстрирующий полностью автоматизированное обнаружение типов. В этом примере сначала загружается сборка 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);
Constructorlnfo [.] ci = t.GetConstructors();
// Использовать первый обнаруженный конструктор.
Parameterlnfо[] 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("ХпВызов методов для объекта reflectOb."); Console.WriteLine();
// Игнорировать наследуемые методы.
MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.Instance | BindingFlags.Public);
// Вызвать каждый метод, foreach(Methodlnfo m in mi) {
Console.WriteLine("Вызов метода {0} ", m.Name);
// Получить параметры.
Parameterlnfо[] 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)) {