Шрифт:
Ключевым членом класса 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 и приватную строковую переменную.
Обратите внимание на то, что метод 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 используется для вызова метода (в нашем случае это конструктор базового класса). С учетом сказанного рассмотрите следующую программную логику конструктора.
Вы, конечно, хорошо знаете, что как только для типа определяется пользовательский конструктор, конструктор, заданный по умолчанию, автоматически "отключается". Чтобы переопределить конструктор, не имеющий аргументов, просто вызовите метод DefineDefaultConstructor типа TypeBuilder, как показано ниже.