Добавить в цитаты Настройки чтения

Страница 263 из 502

<b>  Console.WriteLine(&quot;Найдено: &quot; + temp.Name);</b>

Этой последовательностью кода можно пользоваться всякий раз, когда требуется динамически загружать и опрашивать сборку.

Но сборка совсем не обязательно должна быть исполняемым файлом с расширением .ехе. Сборки могут быть также в файлах динамически компонуемых библиотек (DLL) с расширением .dll. Так, если скомпилировать исходный файл MyClasses.cs в следующей командной строке:

<b>csc /t:library MyClasses.es</b>

то в итоге получится файл MyClasses.dll. Преимущество размещения кода в библиотеке DLL заключается, в частности, в том, что в этом случае метод Main() в исходном коде не нужен, тогда как всем исполняемым файлам требуется определенная точка входа, с которой должно начинаться выполнение программы. Именно поэтому класс Demo содержит метод Main() в качестве такой точки входа. А для библиотеки DLL метод Main() не требуется. Если же класс MyClass нужно превратить в библиотеку DLL, то в вызов метода LoadFrom() придется внести следующее изменение.

<b>Assembly asm = Assembly.LoadFrom(&quot;MyClasses.dll&quot;);</b>

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

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

<b>// Использовать класс MyClass, ничего не зная о нем заранее.</b>

<b>using System;</b>

<b>using System.Reflection;</b>

<b>class ReflectAssemblyDemo {</b>

<b>  static void Main() {</b>

<b>    int val;</b>

<b>    Assembly asm = Assembly.LoadFrom(&quot;MyClasses.exe&quot;);</b>

<b>    Type[] alltypes = asm.GetTypes();</b>

<b>    Type t = alltypes[0]; // использовать первый обнаруженный класс</b>

<b>    Console.WriteLine(&quot;Использовано: &quot; + t.Name);</b>

<b>    ConstructorInfo[] ci = t.GetConstructors();</b>

<b>    // Использовать первый обнаруженный конструктор.</b>

<b>    ParameterInfo[] cpi = ci[0].GetParameters();</b>

<b>    object reflectOb;</b>

<b>    if (cpi.Length &gt; 0) {</b>

<b>      object[] consargs = new object[cpi.Length];</b>

<b>      // Инициализировать аргументы, </b>

<b>      for (int n = 0; n &lt; cpi.Length; n++) consargs[n] = 10 + n * 20;</b>

<b>      // Сконструировать объект.</b>

<b>      reflectOb = ci[0].Invoke(consargs);</b>

<b>    }</b>

<b>    else</b>

<b>      reflectOb = ci[0].Invoke(null);</b>

<b>    Console.WriteLine(&quot;nВызов методов для объекта reflectOb.&quot;);</b>

<b>    Console.WriteLine();</b>

<b>    // Игнорировать наследуемые методы.</b>

<b>    MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly |</b>

<b>                  BindingFlags.Instance | BindingFlags.Public);</b>

<b>    // Вызвать каждый метод,</b>

<b>    foreach (MethodInfo m in mi) {</b>

<b>      Console.WriteLine(&quot;Вызов метода {0} &quot;, m.Name);</b>

<b>      // Получить параметры.</b>

<b>      ParameterInfo[] pi = m.GetParameters();</b>

<b>      // Выполнить методы,</b>

<b>      switch (pi.Length) {</b>

<b>        case 0: // аргументы отсутствуют </b>

<b>          if (m.ReturnType == typeof(int)) {</b>

<b>            val = (int)m.Invoke(reflectOb, null);</b>

<b>            Console.WriteLine(&quot;Результат: &quot; + val);</b>

<b>          }</b>

<b>          else if (m.ReturnType == typeof(void)) {</b>

<b>            m.Invoke(reflectOb, null);</b>

<b>          }</b>

<b>          break;</b>