Как упоминалось ранее, для определения конструктора текущего типа можно применять метод TypeBuilder.DefineConstructor()
HelloClass, в тело конструктора необходимо вставить низкоуровневый код CIL, который будет отвечать за присваивание входного параметра внутренней закрытой строке. Чтобы получить объект типа ILGenerator, понадобится вызвать метод GetILGenerator() из соответствующего типа "построителя" (в данном случае ConstructorBuilder).Помещение кода CIL в реализацию членов осуществляется с помощью метода Emit()
ILGenerator. В самом методе Emit() часто используется тип класса Opcodes, который открывает доступ к набору кодов операций CIL через свойства только для чтения. Например, свойство Opcodes.Ret обозначает возвращение из вызова метода .Opcodes.Stfid создает присваивание значения переменной-члену, a Opcodes.Call применяется для вызова заданного метода (конструктора базового класса в данном случае). Итак, логика для реализации конструктора будет выглядеть следующим образом:// Создать специальный конструктор, принимающий
// единственный аргумент типа string.
Type[] constructorArgs = new Type[1];
constructorArgs[0] = typeof(string);
ConstructorBuilder constructor =
helloWorldClass.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
constructorArgs);
// Выпустить необходимый код CIL для конструктора.
ILGenerator constructorIl = constructor.GetILGenerator();
constructorIl.Emit(OpCodes.Ldarg_0);
Type objectClass = typeof(object);
ConstructorInfo superConstructor =
objectClass.GetConstructor(new Type[0]);
constructorIl.Emit(OpCodes.Call, superConstructor);
// Загрузить в стек указатель this объекта.
constructorIl.Emit(OpCodes.Ldarg_0);
constructorIl.Emit(OpCodes.Ldarg_1);
// Загрузить входной аргумент в виртуальный стек и сохранить его в msgField
constructorIl.Emit(OpCodes.Stfld, msgField);
constructorIl.Emit(OpCodes.Ret);
Как вам теперь уже известно, в результате определения специального конструктора для типа стандартный конструктор молча удаляется. Чтобы снова определить конструктор без аргументов, нужно просто вызвать метод DefineDefaultConstructor()
TypeBuilder:// Создать стандартный конструктор.
helloWorldClass.DefineDefaultConstructor(
MethodAttributes.Public);
Выпуск метода SayHello()
В заключение давайте исследуем процесс выпуска метода SayHello()
MethodBuilder из переменной helloWorldClass. После этого можно определить сам метод и получить внутренний объект типа ILGenerator для вставки необходимых инструкций CIL:// Создать метод SayHello.
MethodBuilder sayHiMethod = helloWorldClass.DefineMethod(
"SayHello", MethodAttributes.Public, null, null);
methodIl = sayHiMethod.GetILGenerator();
// Вывести строку на консоль.
methodIl.EmitWriteLine("Hello from the HelloWorld class!");
methodIl.Emit(OpCodes.Ret);
Здесь был определен открытый метод (т.к. указано значение MethodAttributes.Public
null в вызове DefineMethod()). Также обратите внимание на вызов EmitWriteLine(). Посредством данного вспомогательного метода класса ILGenerator можно записать строку в стандартный поток вывода, приложив минимальные усилия.Использование динамически сгенерированной сборки