Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 87 стр.

UptoLike

В отличие от Metadata Unmanaged API, библиотека рефлексии содер-
жит средства для генерации CIL-кода. Для этого предназначен класс
ILGenerator. Он позволяет после создания объекта MethodBuilder (или
ConstructorBuilder) сгенерировать для соответствующего метода (или
конструктора) поток инструкций.
Рис. 4.6. Последовательность создания метаданных
В следующем примере библиотека рефлексии используется для гене-
рации сборки .NET, состоящей из одного глобального метода main, выво-
дящего на экран сообщение «Hello, World!»:
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
class HelloGenerator
{
static void Main(string[] args)
{
AppDomain appDomain = Thread.GetDomain();
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = “hello.exe”;
AssemblyBuilder assembly =
appDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.RunAndSave
);
ModuleBuilder module =
assembly.DefineDynamicModule(
“hello.exe”, “hello.exe”
Анализ кода на CIL
161
MethodInfo printer =
typeof(TestClass).GetMethod(“print”,flags);
printer.Invoke(a, null);
}
Путем внесения небольших изменений в CallMethodDemo мы можем
добиться того, что объект класса TestClass будет также создаваться через
рефлексию (с помощью вызова его конструктора):
static void CallMethodDemo2()
{
Type t = typeof(TestClass);
BindingFlags flags = (BindingFlags)
(BindingFlags.NonPublic | BindingFlags.Instance);
ConstructorInfo ctor = t.GetConstructor(new Type[0]);
MethodInfo printer = t.GetMethod(“print”,flags);
object a = ctor.Invoke(null);
printer.Invoke(a, null);
}
А теперь продемонстрируем, как через рефлексию можно получить
значение поля объекта. Это достигается путем вызова метода GetField объ-
екта класса Type:
static void GetFieldDemo()
{
TestClass a = new TestClass();
BindingFlags flags = (BindingFlags)
(BindingFlags.NonPublic |
BindingFlags.Instance);
FieldInfo val =
typeof(TestClass).GetField(“val”,flags);
Console.WriteLine(val.GetValue(a));
}
4.4.2.3. Генерация метаданных и CIL-кода
Для генерации метаданных в библиотеке рефлексии предназначены
классы пространства имен System.Reflection.Emit. Создание новой сборки
начинается с создания экземпляра класса AssemblyBuilder. Далее путем вы-
зова методов класса AssemblyBuilder создается нужное количество модулей
(объектов класса ModuleBuilder), в модулях создаются типы (объекты клас-
са TypeBuilder), а в типах – конструкторы, методы и поля (объекты классов
ConstructorBuilder, MethodBuilder и FieldBuilder, соответственно). То есть
при генерации метаданных идеология такая же, как и при чтении их из го-
товой сборки (на рис. 4.6 представлена схема, показывающая последова-
тельность создания метаданных).
160
CIL и системное программирование в Microsoft .NET
AssemblyBuilder
ModuleBuilder
TypeBuilder
ParameterBuilder
ILGenerator
FieldBuilder
MethodBuilder
ConstructorBuilder
PropertyBuilder
160                          CIL и системное программирование в Microsoft .NET   Анализ кода на CIL                                                    161


       MethodInfo printer =                                                           В отличие от Metadata Unmanaged API, библиотека рефлексии содер-
         typeof(TestClass).GetMethod(“print”,flags);                             жит средства для генерации CIL-кода. Для этого предназначен класс
       printer.Invoke(a, null);                                                  ILGenerator. Он позволяет после создания объекта MethodBuilder (или
     }                                                                           ConstructorBuilder) сгенерировать для соответствующего метода (или
     Путем внесения небольших изменений в CallMethodDemo мы можем                конструктора) поток инструкций.
добиться того, что объект класса TestClass будет также создаваться через
рефлексию (с помощью вызова его конструктора):                                              AssemblyBuilder       FieldBuilder
     static void CallMethodDemo2()
     {
       Type t = typeof(TestClass);
                                                                                             ModuleBuilder       MethodBuilder       ParameterBuilder
       BindingFlags flags = (BindingFlags)
        (BindingFlags.NonPublic | BindingFlags.Instance);
       ConstructorInfo ctor = t.GetConstructor(new Type[0]);
                                                                                              TypeBuilder     ConstructorBuilder         ILGenerator
       MethodInfo printer = t.GetMethod(“print”,flags);
       object a = ctor.Invoke(null);
       printer.Invoke(a, null);
     }                                                                                                          PropertyBuilder
     А теперь продемонстрируем, как через рефлексию можно получить
значение поля объекта. Это достигается путем вызова метода GetField объ-              Рис. 4.6. Последовательность создания метаданных
екта класса Type:
     static void GetFieldDemo()                                                      В следующем примере библиотека рефлексии используется для гене-
     {                                                                           рации сборки .NET, состоящей из одного глобального метода main, выво-
       TestClass a = new TestClass();                                            дящего на экран сообщение «Hello, World!»:
       BindingFlags flags = (BindingFlags)                                           using System;
         (BindingFlags.NonPublic |                                                   using System.Threading;
           BindingFlags.Instance);                                                   using System.Reflection;
       FieldInfo val =                                                               using System.Reflection.Emit;
          typeof(TestClass).GetField(“val”,flags);                                   class HelloGenerator
       Console.WriteLine(val.GetValue(a));                                           {
     }                                                                                  static void Main(string[] args)
                                                                                        {
4.4.2.3. Генерация метаданных и CIL-кода                                                  AppDomain appDomain = Thread.GetDomain();
      Для генерации метаданных в библиотеке рефлексии предназначены                       AssemblyName assemblyName = new AssemblyName();
классы пространства имен System.Reflection.Emit. Создание новой сборки                    assemblyName.Name = “hello.exe”;
начинается с создания экземпляра класса AssemblyBuilder. Далее путем вы-                  AssemblyBuilder assembly =
зова методов класса AssemblyBuilder создается нужное количество модулей                     appDomain.DefineDynamicAssembly(
(объектов класса ModuleBuilder), в модулях создаются типы (объекты клас-                       assemblyName,
са TypeBuilder), а в типах – конструкторы, методы и поля (объекты классов                      AssemblyBuilderAccess.RunAndSave
ConstructorBuilder, MethodBuilder и FieldBuilder, соответственно). То есть                     );
при генерации метаданных идеология такая же, как и при чтении их из го-                   ModuleBuilder module =
товой сборки (на рис. 4.6 представлена схема, показывающая последова-                       assembly.DefineDynamicModule(
тельность создания метаданных).                                                                “hello.exe”, “hello.exe”