Язык программирования C#9 и платформа .NET5
Часть 358 из 642 Информация о книге
constructorIl.Emit(OpCodes.Stfld, msgField);constructorIl.Emit(OpCodes.Ret);<b> // Создать стандартный конструктор.</b>helloWorldClass.DefineDefaultConstructor(MethodAttributes.Public);<b> // Создать метод GetMsg().</b>MethodBuilder getMsgMethod = helloWorldClass.DefineMethod("GetMsg",MethodAttributes.Public,typeof(string),null);ILGenerator methodIl = getMsgMethod.GetILGenerator();methodIl.Emit(OpCodes.Ldarg_0);methodIl.Emit(OpCodes.Ldfld, msgField);methodIl.Emit(OpCodes.Ret);<b> // Создать метод SayHello().</b>MethodBuilder sayHiMethod = helloWorldClass.DefineMethod("SayHello", MethodAttributes.Public, null, null);methodIl = sayHiMethod.GetILGenerator();methodIl.EmitWriteLine("Hello from the HelloWorld class!");methodIl.Emit(OpCodes.Ret);<b> // Выпустить класс HelloWorld.</b>helloWorldClass.CreateType();return builder;}Выпуск сборки и набора модулей
Тело метода начинается с установления минимального набора характеристик сборки с применением типов
иAssemblyName(определенных в пространстве именVersion). Затем производится получение объекта типаSystem.Reflectionчерез статический методAssemblуBuilder.AssemblyBuilder.DefineDynamicAssembly()При вызове метода
должен быть указан режим доступа к определяемой сборке, наиболее распространенные значения которого представлены в табл. 19.9.DefineDynamicAssembly()Следующая задача связана с определением набора модулей (и имени) для новой сборки. Метод
возвращает ссылку на действительный объект типаDefineDynamicModule():ModuleBuilder// Создать новую сборку.var builder = AssemblyBuilder.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.Run);Роль типа ModuleBuilder
Тип
играет ключевую роль во время разработки динамических сборок. Как и можно было ожидать,ModuleBuilderподдерживает несколько членов, которые позволяют определять набор типов, содержащихся внутри модуля (классы, интерфейсы, структуры и т.д.), а также набор встроенных ресурсов (таблицы строк, изображения и т.п.). В табл. 19.10 описаны два метода, относящиеся к созданию. (Обратите внимание, что каждый метод возвращает объект связанного типа, который представляет тип, подлежащий созданию.)ModuleBuilderОсновным членом класса
является методModuleBuilder. Кроме указания имени типа (в виде простой строки) с помощью перечисленияDefineType()можно описывать формат этого типа. В табл. 19.11 приведены избранные члены перечисленияSystem.Reflection.TypeAttributes.TypeAttributesВыпуск типа HelloClass и строковой переменной-члена
Теперь, когда вы лучше понимаете роль метода
, давайте посмотрим, как можно выпустить открытый тип классаModuleBuilder.CreateType()и закрытую строковую переменную:HelloWorld<b>// Определить открытый класс по имени HelloWorld.</b>TypeBuilder helloWorldClass =module.DefineType("MyAssembly.HelloWorld",TypeAttributes.Public);<b>// Определить закрытую переменную-член типа String по имени theMessage.</b>FieldBuilder msgField = helloWorldClass.DefineField("theMessage",Type.GetType("System.String"),attributes: FieldAttributes.Private);Обратите внимание, что метод
предоставляет доступ к объекту типаTypeBuilder.DefineField(). В классеFieldBuilderтакже определены дополнительные методы, которые обеспечивают доступ к другим типам "построителей". Например, методTypeBuilderвозвращает объект типаDefineConstructor(), методConstructorBuilder— объект типаDefineProperty()и т.д.PropertyBuilderВыпуск конструкторов
Как упоминалось ранее, для определения конструктора текущего типа можно применять метод
. Однако когда дело доходит до реализации конструктораTypeBuilder.DefineConstructor(), в тело конструктора необходимо вставить низкоуровневый код CIL, который будет отвечать за присваивание входного параметра внутренней закрытой строке. Чтобы получить объект типаHelloClass, понадобится вызвать методILGeneratorиз соответствующего типа "построителя" (в данном случаеGetILGenerator()).ConstructorBuilderПомещение кода CIL в реализацию членов осуществляется с помощью метода
классаEmit(). В самом методеILGeneratorчасто используется тип классаEmit(), который открывает доступ к набору кодов операций CIL через свойства только для чтения. Например, свойствоOpcodesобозначает возвращение из вызова методаOpcodes.Retсоздает присваивание значения переменной-члену, a.Opcodes.Stfidприменяется для вызова заданного метода (конструктора базового класса в данном случае). Итак, логика для реализации конструктора будет выглядеть следующим образом:Opcodes.Call


