| Метод | Описание |
|---|---|
| BeginCatchBlock | Начинает блок catch |
| BeginExceptionBlock | Начинает блок неотфильтрованного исключения |
| BeginFinallyBlock | Начинает блок finally |
| BeginScope | Начинает лексический контекст |
| DeclareLocal | Объявляет локальную переменную |
| DefineLabel | Объявляет новую метку |
| Emit | Является перегруженным и позволяет генерировать коды операций CIL |
| EmitCall | Вставляет код операции call или callvirt в поток CIL |
| EmitWriteLine | Генерирует вызов Console.WriteLine с различными типами значений |
| EndExceptionBlock | Завершает блок исключения |
| EndScope | Завершает лексический контекст |
| ThrowException | Создает инструкцию для генерирования исключения |
| UsingNamespace | Указывает пространство имен, которое будет использоваться для оценки локальных переменных и наблюдаемых значений в текущем активном лексическом контексте |
Ключевым методом ILGenerator является метод Emit, который работает в совокупности с типом класса System.Reflection.Emit.OpCodes. Как уже упоминалось в этой главе, данный тип открывает большой набор доступных только для чтения полей, отображающихся в коды операций CIL. Полностью эти члены описаны в оперативно доступной системе справки, но целый ряд примеров вы сможете увидеть и на следующих страницах.
Генерирование динамического компоновочного блока
Чтобы проиллюстрировать процесс определения компоновочного блока .NET в среде выполнения, давайте создадим одномодульный динамический компоновочный блок с именем MyAssembly.dll. В этом модуле будет содержаться класс HelloWorld. Тип HelloWorld поддерживает конструктор, используемый по умолчанию, и пользовательский конструктор для присваивания значения приватной переменной (theMessage) типа string. Кроме того, HelloWorld предлагает открытый метод экземпляра с именем SayHello, который выводит приветствие в стандартный поток ввода-вывода, а также еще один метод экземпляра, GetMsg, который возвращает внутреннюю приватную строку. В результате вы должны программно сгенерировать следующий тип класса.
// Этот класс будет создан в среде выполнения
// с помощью System.Reflection.Emit.
public class HelloWorld {
private string theMessage;
HelloWorld {}
HelloWorld(string s) { theMessage = s; }
public string GetMsg { return theMessage; }
public void SayHello {
System.Console.WriteLine("Привет от класса HelloWorld!");
}
}
Предположим, вы cоздали новый проект консольного приложения в Visual Studio 2005, назвав его DynAsmBuilder. Переименуйте исходный класс в MyAsmBuilder и определите статический метод с именем CreateMyAsm. Этот единственный метод будет ответственен за следующее:
• определение характеристик динамического компоновочного блока (имя, версия и т.д.);
• реализацию тина HelloClass;
• запись компоновочного блока, сгенерированного в памяти, в физический файл.
Также отметим, что метод CreateMyAsm использует в качестве единственного параметра тип System.AppDomain, который будет использоваться для получения доступа к типу AssemblyBuilder, связанному с текущим доменом приложения (см. главу 13, где обсуждаются домены приложений .NET). Вот полный программный код, с последующим анализом.
// Вызывающая сторона посылает тип AppDomain.
public static void CreateMyAsm(AppDomain currAppDomain) {
// Установка общих характеристик компоновочного блока.
AssemblyName assemblyName = new AssemblyName;
assemblyName.Name = "MyAssembly";
assemblyName.Version = new Version("1.0.0.0");
// Создание нового компоновочного блока
// в рамках текущего домена приложения.