KnigaRead.com/
KnigaRead.com » Разная литература » Прочее » Герберт Шилдт - C# 4.0 полное руководство - 2011

Герберт Шилдт - C# 4.0 полное руководство - 2011

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн "Герберт Шилдт - C# 4.0 полное руководство - 2011". Жанр: Прочее издательство неизвестно, год неизвестен.
Перейти на страницу:

А теперь рассмотрим порядок применения рефлексии для конструирования объекта класса MyClass. Сначала получается перечень открытых конструкторов в следующей строке кода.

Constructorlnfo[] ci = t.GetConstructors ();

Затем для наглядности примера выводятся полученные конструкторы. После этого осуществляется поиск по списку конструктора, принимающего два аргумента, как показано в приведенном ниже фрагменте кода.

for(x=0; х < ci.Length; х++)    {

Parameterlnfo[] pi = ci[x].GetParameters(); if(pi.Length == 2) break;

}

Если такой конструктор найден, как в данном примере, то в следующем фрагменте кода получается экземпляр объекта заданного типа.

// Сконструировать объект, object[] consargs = new object[2]; consargs[0] = 10; consargs[1] = 20;

object reflectOb = ci[x].Invoke(consargs);

После вызова метода Invoke () переменная экземпляра reflectOb будет ссылаться на объект типа MyClass. А далее в программе выполняются соответствующие методы для экземпляра этого объекта.

Следует, однако, иметь в виду, что ради простоты в данном примере предполагается наличие лишь одного конструктора с двумя аргументами типа int. Очевидно, что в реальном коде придется дополнительно проверять соответствие типов каждого параметра и аргумента.

Получение типов данных из сборок

В предыдущем примере все сведения о классе MyClass были получены с помощью рефлексии, за исключением одного элемента: типа самого класса MyClass. Несмотря на то что сведения о классе получались в предыдущем примере динамически, этот пример опирался на тот факт, что имя типа MyClass было известно заранее и использовалось в операторе typeof для получения объекта класса Туре, по отношению к которому осуществлялось косвенное или непосредственное обращение к методам рефлексии. В некоторых случаях такой подход может оказаться вполне пригодным, но истинные преимущества рефлексии проявляются лишь тогда, когда доступные в программе типы данных определяются динамически в результате анализа содержимого других сборок.

Как следует из главы 16, сборка несет в себе сведения о типах классов, структур и прочих элементов данных, которые в ней содержатся. Прикладной интерфейс Reflection API позволяет загрузить сборку, извлечь сведения о ней и получить экземпляры объектов любых открыто доступных в ней типов. Используя этот механизм, программа может выявлять свою среду и использовать те функциональные возможности, которые могут оказаться доступными без явного их определения во время компиляции. Это очень эффективный и привлекательный принцип. Представьте себе, например, программу, которая выполняет роль "браузера типов", отображая типы данных, доступные в системе, или же инструментальное средство разработки, позволяющее визуально составлять программы из различных типов данных, поддерживаемых в системе. А поскольку все сведения о типах могут быть извлечены и проверены, то ограничений на применение рефлексии практически не существует.

Для получения сведений о сборке сначала необходимо создать объект класса Assembly. В классе Assembly открытый конструктор не определяется. Вместо этого объект класса Assembly получается в результате вызова одного из его методов. Так, для загрузки сборки по заданному ее имени служит метод LoadFrom (). Ниже приведена его соответствующая форма:

static Assembly LoadFrom(string файл_сборки)

где файл_ сборки-обозначает конкретное имя файла сборки.

Как только будет получен объект класса Assembly, появится возможность обнаружить определенные в нем типы данных, вызвав для него метод Get Types () в приведенной ниже общей форме.

Туре [ ] GetTypesO

Этот метод возвращает массив типов, содержащихся в сборке.

Для того чтобы продемонстрировать порядок обнаружения типов в сборке, потребуются два исходных файла. Первый файл будет содержать ряд классов, обнаруживаемых в коде из второго файла. Создадим сначала файл MyClasses . cs, содержащий следующий код.

// Файл, содержащий три класса и носящий имя MyClasses.cs.

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 ("Значение x:    {0},    значение у: {1}", x, у);

}

}

class AnotherClass { string msg;

public AnotherClass(string str) { msg = str;

}

public void Show()    {

Console.WriteLine(msg);

class Demo {

static void Main() {

Console.WriteLine("Это заполнитель.");

}

}

Этот файл содержит класс MyClass, неоднократно использовавшийся в предыдущих примерах. Кроме того, в файл добавлены второй класс AnotherClass и третий класс Demo. Следовательно, сборка, полученная из исходного кода, находящегося в этом исходном файле, будет содержать три класса. Затем этот файл компилируется, и из него формируется исполняемый файл MyClasses . ехе. Именно эта сборка и будет опрашиваться программно.

Ниже приведена программа, в которой будут извлекаться сведения о файле сборки MyClasses . ехе. Ее исходный текст составляет содержимое второго файла.

/* Обнаружить сборку, определить типы и создать объект с помощью рефлексии. */

using System;

using System.Reflection;

class ReflectAssemblyDemo { 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 = с.GetParameters(); for(int i=0; i < pi.Length; i++)    {

Console.Write(pi[i].ParameterType.Name + " " + pi[i].Name);

■ if(i+1 < 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;

}

else

Console.WriteLine("Найден конструктор с двумя параметрами.n");

// Сконструировать объект, object[] consargs = new object[2]; consargs[0] = 10; consargs[1] = 20;

object reflectOb = ci[x].Invoke(consargs) ;

Console.WriteLine("пВызов методов для объекта reflectOb."); Console.WriteLine();

MethodInfo[] mi = t.GetMethods();

// Вызвать каждый метод, foreach(Methodlnfo 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[l] = 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)    {

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

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*