Вход/Регистрация
ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
вернуться

Троелсен Эндрю

Шрифт:

Ключевым членом класса 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]);

constructorIL.Emit(OpCodes.Call, superConstructor); // Вызов конструктора базового класса.

// Загрузка указателя 'this' объекта в стек.

constructorIL.Emit(OpCodes.Ldarg_0);

// Загрузка входного аргументе в стек и сохранения в msgField.

constructorIL.Emit(Opcodes.Ldarg_1);

constructorIL.Emit(Opcodes.Stfld, msgField); // Присвоение msgField.

constructorIL.Emit(Opcodes.Ret); // Возврат.

Вы, конечно, хорошо знаете, что как только для типа определяется пользовательский конструктор, конструктор, заданный по умолчанию, автоматически "отключается". Чтобы переопределить конструктор, не имеющий аргументов, просто вызовите метод DefineDefaultConstructor типа TypeBuilder, как показано ниже.

  • Читать дальше
  • 1
  • ...
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: