Натолкнулся в нете на следующую статейку.
Иногда нам требуется динамически создать некий код. Естественно, что этот код у нас будет храниться в некоторой сборке. При этом сама созданная динамически сборка может существовать только в памяти или же может быть сохраненной на диск в виде файла. Сейчас мы посмотрим, как это можно сделать.
Для начала небольшое замечание по порядку создания соответствующих объектов. Сначала мы должны сгенерировать сборку, затем на основании этой сборки - модуль, потом на основании этого модуля - тип (например, класс), потом на основании этого типа (класса) - его члены (конструкторы, методы и т. п.). И, уже в самом конце, мы создаем непосредственно сгенерированный на предыдущих шагах тип.
Вот пример такого кода:
[c#]
// Создание имени сборки.
AssemblyName an = new AssemblyName("MyAssembly");
an.Version = new Version("1.0.0.0");
// Создание сборки.
AssemblyBuilder ab;
ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save);
// Создание модуля в сборке.
ModuleBuilder mb = ab.DefineDynamicModule("MyModule", "My.dll");
// Создание типа в сборке.
TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);
// Создание конструктора без параметров.
ConstructorBuilder cb0 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
// Добавление кода для конструктора.
ILGenerator il0 = cb0.GetILGenerator();
il0.Emit(OpCodes.Ret);
// Создание конструктора с параметром типа string.
ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard, new Type[] { typeof(string)});
// Добавление кода для конструктора.
ILGenerator il = cb.GetILGenerator();
il.EmitWriteLine("Constructor");
il.Emit(OpCodes.Ret);
// Непосредственное создание типа.
tb.CreateType();
// Сохранение типа в файл.
ab.Save("qqq.dll");
[/c#]
Приведенный код при запуске создаст на жестком диске файл qqq.dll, в котором будет класс с 2-я конструкторами, причем второй конструктор будет при вызове выводить строчку "Constructor".
Несколько пояснений по коду.
Первое. Очень часто при создании типов и членов этих типов надо указать их атрибуты (модификаторы доступа типа public и т. п.). Это мы делаем через перечисления TypeAttributes и MethodAttributes, которое содержит соотвествующие значения (Public, например). Несколько необходимых значений из этих перечислений можно соединить через побитовое "или".
Второе. Метод Emit класса ILGenerator в качестве параметра принимает перечисление OpCodes, которое фактически содержит инструкции на языке IL - языке, который является аналогом для .NET обычного ассемблера. Это означает, что его инструкции не столь очевидны для реального программирования - именно поэтому в качестве примера таких IL-инструкций и была приведена самая простая из них - а именно выход из функции (OpCodes.Ret).
Кто нибудь применял данную методику? Если да то в каких целях? В каких задачах он используется?
Заранее спасибо