Книга: ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
Генерирование конструкторов
Генерирование конструкторов
Как уже упоминалось выше, для определения конструктора типа может использоваться метод 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, как показано ниже.
// Восстановление конструктора, заданного по умолчанию.
helloWorldClass.DefineDefaultConstructor(MethodAttributes.Public);
Следующий вызов порождает стандартный CIL-код для определения конструктора, заданного по умолчанию.
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed {
.maxstack 1
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
- Исследование пространства имен System.Reflection.Emit
- Роль System.Reflection.Emit.ILGenerator
- Генерирование динамического компоновочного блока
- Генерирование компоновочного блока и набора модулей
- Роль типа ModuleBuilder
- Генерирование типа HelloClass и принадлежащей ему строковой переменной
- Генерирование конструкторов
- Генерирование метода HelloWorld()
- Использование динамически сгенерированного компоновочного блока
- Генерирование типа HelloClass и принадлежащей ему строковой переменной
- Генерирование метода HelloWorld()
- Генерирование исключений
- Перегрузка конструкторов
- Генерирование события оплаты
- Генерирование полосы навигации
- Генерирование исключений вручную
- 5.28. Генерирование случайных чисел
- 16.2. Генерирование файлов классов для сущностей Core Data
- Наследование конструкторов
- Генерирование HTML-содержимого
- Генерирование концепции