Книга: ЯЗЫК ПРОГРАММИРОВАНИЯ С# 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
}

Оглавление книги


Генерация: 1.802. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз