Таблица 15.11. Подборка членов типа ModuleBuilder
| Метод |
Описание |
| DefineEnum() |
Используется для генерирования определения перечня .NET |
| DefineResource() |
Определяет управляемый встроенный ресурс, который должен храниться в данном модуле |
| DefineType() |
Конструирует TypeBuilder, который позволяет определять типы значений, интерфейсы и типы класса (в том числе и делегаты) |
Ключевым членом класса ModuleBuilder, о котором следует знать, является DefineType(). Вдобавок к указанию имени типа (в виде простой строки), вы должны использовать перечень System.Reflection.TypeAttributes, чтобы непосредственно описать формат типа. Основные члены перечня TypeAttributes представлены в табл. 15.12.
Таблица 15.12.Подборка элементов перечня TypeAttributes
| Член |
Описание |
| Abstract |
Указывает абстрактный тип |
| Class |
Указывает тип класса |
| Interface |
Указывает тип интерфейса |
| NestedAssembly |
Указывает, что класс вложен в область видимости компоновочного блока и поэтому доступен только для методов соответствующего компоновочного блока |
| NestedFamAndAssem |
Указывает, что класс вложен в область видимости семейства и компоновочного блока и поэтому доступен только для методов, принадлежащих пересечению соответствующего семейства и компоновочного блока |
| NestedFamily |
Указывает, что класс вложен в область видимости семейства и поэтому доступен только для методов соответствующего типа и его подтипов |
| NestedFamORAssem |
Указывает, что класс вложен в область видимости семейства или компоновочного блока и поэтому доступен только для методов, принадлежащих объединению соответствующего семейства и компоновочного блока |
| NestedPrivate |
Указывает вложенный класс с приватной областью видимости |
| NestedPublic |
Указывает вложенный класс с общедоступной областью видимости |
| NotPublic |
Указывает класс, не являющийся открытым |
| Public |
Указывает открытый класс |
| Sealed |
Указывает изолированный класс, который не может быть расширен |
| Serializable |
Указывает класс, допускающий сериализацию |
Генерирование типа HelloClass и принадлежащей ему строковой переменной
Теперь вы понимаете роль метода ModuleBuilder.CreateType(), и пришло время выяснить, как сгенерировать открытый тип класса HelloWorld и приватную строковую переменную.
// Определение открытого класса MyAssembly.HelloWorld.
TypeBuilder helloWorldClass = module.DefineType("MyAssembly.HelloWorld", TypeAttributes.Public);
// Определение принадлежащей классу приватной переменной String
// с именем theMessage.
FieldBuilder msgField =hellоWоrldclass.DefineField("theMessage", typeof(string), FieldAttributes.Private);
Обратите внимание на то, что метод TypeBuilder.DefineField() обеспечивает доступ к типу FieldBuilder. Класс TypeBuilder определяет также другие методы, обеспечивающие доступ к другим типам "построителя". Например, DefineConstructor() возвращает ConstructorBuilder.DefineProperty() – PropertyBuilder и т.д.
Генерирование конструкторов
Как уже упоминалось выше, для определения конструктора типа может использоваться метод TypeBuilder.DefineConstructor(). Однако в нашей реализации конструктора HelloClass, чтобы назначить поступающий параметр внутренней приватной строке, мы добавим CIL-код в тело конструктора непосредственно. Чтобы получить тип ILGenerator, вызывается метод GetILGenerator() соответствующего типа "построителя", на который имеется ссылка (в данном случае это тип ConstructorBuilder).
Метод Emit() класса ILGenerator отвечает за размещение CIL-кода в реализации члена. Сам метод Emit() часто использует тип класса OpCodes, который с помощью полей, доступных только для чтения, открывает доступ к набору кодов операций CIL. Например, OpCodes.Ret указывает возврат вызова метода, OpCodes.Stfld выполняет присваивание значения члену-переменной, a OpCodes.Call используется для вызова метода (в нашем случае это конструктор базового класса). С учетом сказанного рассмотрите следующую программную логику конструктора.
// Создание пользовательского конструктора, имеющего
// один аргумент System.String.
Type[] constructorArgs = new Type[1];
constructorArgs[0] = typeof(string);
ConstructorBuilder constructor = helloWorldClass.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, constructorArgs);
// Теперь в конструктор добавляется необходимый CIL-код.
ILGenerator constructorIL = constructor.GеtILGenerator();
constructorIL.Emit( OpCodes.Ldarg_0);
Type objectClass = typeof(object);
ConstructorInfo superConstructor = objectClass.GetConstructor(new Type[0]);
Читать дальше