///-----------------------------------------------------------------------------------
/// Вот такой класс в составе однофайловой сборки DynamicAssm
/// предполагается построить в ходе выполнения сборки DynamicAssemblyGenerator.
///
/// public class DynamicTest
/// {
/// private string messageString;
/// // Конструктор
/// DynamicTest(string strKey)
/// {
/// messageString = strKey;
/// }
///
/// // Методы
/// public void ShowMessageString()
/// {
/// System.Console.WriteLine(“the value of messageString is {0}...”, messageString);
/// }
///
/// public string GetMessageString()
/// {
/// return messageString;
/// }
///
///}
///-----------------------------------------------------------------------------------
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace DynamicAssemblyGenerator
{
/// <summary>
/// AssemblyGenerator - класс, реализующий динамическую генерацию сборки.
/// </summary>
class AssemblyGenerator
{
public string XXX;
public string ZZZ()
{
return XXX;
}
public int CreateAssm(AppDomain currentAppDomain)
{
// Создание сборки начинается с присвоения ей имени и номера версии.
// Для этого используется класс AssemblyName.
// Определяется имя и версия создаваемой сборки.
AssemblyName assmName = new AssemblyName();
assmName.Name = “DynamicAssm”;
assmName.Version = new Version(“1.0.0.0”);
// Создаётся сборка в памяти. В рамках текущего домена приложения.
// С использованием режима доступа, который задаётся одним из элементов перечисления:
// Run - динамическая сборка выполняется, но не сохраняется.
// RunAndSave - динамическая сборка выполняется и сохраняется.
// Save - динамическая сборка не выполненяется, но сохраняется.
AssemblyBuilder assembly = currentAppDomain.DefineDynamicAssembly(assmName,
AssemblyBuilderAccess.Save);
// Создаётся однофайловая сборка, в которой имя единственного модуля совпадает с именем самой сборки.
ModuleBuilder module = assembly.DefineDynamicModule(“DynamicAssm”,
«DynamicAssm.dll» );
// Создаётся и определяется класс DynamicTest класс. Метод module.DefineType позволяет
// встраивать в модуль класс, структуру или интерфейс.
// Вторым параметром метода идёт элемент перечисления. Таким образом создаётся объект-заготовка
// класса, который далее дополняется полями, свойствами, методами...
TypeBuilder dynamicTestClass = module.DefineType(“DynamicAssm.DynamicTest”,
TypeAttributes.Public);
// Объявляется данное-член класса DynamicTest.
// Предполагается объявить “private string messageString;”
FieldBuilder messageStringField = dynamicTestClass.DefineField(“messageString”,
Type.GetType(“System.String”),
FieldAttributes.Private);
// Объекты для генерации элементов класса. В данном конкретном случае используются при генерации:
ILGenerator bodyConstructorIL; // - тела конструктора.
ILGenerator methodIL; // - тела метода.
// Объявляется конструктор.__________________________________________________________
// Предполагается объявить «DynamicTest(string strKey)...»
Type[] constructorArgs = new Type[1];
constructorArgs[0] = Type.GetType(“System.String”);
ConstructorBuilder constructor = dynamicTestClass.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
constructorArgs);
// Тело конструктора. Представляет собой IL код,
// который встраивается в тело конструктора посредством метода Emit,
// определённого в классе ILGenerator (см. Объекты для генерации элементов класса).
// Метод Emit в качестве параметров использует перечисление OpCodes (коды операций),
// которые определяют допустимые команды IL.
bodyConstructorIL = constructor.GetILGenerator();
bodyConstructorIL.Emit(OpCodes.Ldarg_0);
Type objectClass = Type.GetType(“System.Object”);
ConstructorInfo greatConstructor = objectClass.GetConstructor(new Type[0]);
bodyConstructorIL.Emit(OpCodes.Call, greatConstructor);
bodyConstructorIL.Emit(OpCodes.Ldarg_0);
bodyConstructorIL.Emit(OpCodes.Ldarg_1);
bodyConstructorIL.Emit(OpCodes.Stfld,messageStringField);
bodyConstructorIL.Emit(OpCodes.Ret);
// Конец объявления конструктора.____________________________________________________
// Объявление метода public string GetMessageString()________________________________
MethodBuilder GetMessageStringMethod = dynamicTestClass.DefineMethod(
“GetMessageString”,
MethodAttributes.Public,
Type.GetType(“System.Sring”),
null);
// IL_0000: ldarg.0
// IL_0001: ldfld string DynamicAssemblyGenerator.AssemblyGenerator::XXX
// IL_0006: stloc.0
// IL_0007: br.s IL_0009
// IL_0009: ldloc.0
// IL_000a: ret
//System.Reflection.Emit.Label label = new Label();
// Тело метода...
methodIL = GetMessageStringMethod.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Ldfld,messageStringField);
methodIL.Emit(OpCodes.Ret);
// Конец объявления метода public string GetMessageString()___________________________
// Объявление метода public string ShowMessageString()________________________________
MethodBuilder ShowMessageStringMethod = dynamicTestClass.DefineMethod(
“ShowMessageString”,
MethodAttributes.Public,
null,
null);
// Тело метода...
methodIL = ShowMessageStringMethod.GetILGenerator();
methodIL.EmitWriteLine(“This is ShowMessageStringMethod...”);
methodIL.Emit(OpCodes.Ret);
// Конец объявления метода public string ShowMessageString()__________________________
// Вот и завершили динамическое объявление класса.
dynamicTestClass.CreateType();
// Остаётся его сохранить на диск.
assembly.Save(“DynamicAssm.dll”);
return 0;
}
static void Main(string[] args)
{
// Создаётся и сохраняется динамическая сборка.
AssemblyGenerator ag = new AssemblyGenerator();
ag.CreateAssm(AppDomain.CurrentDomain);
// Для наглядности! создаются НОВЫЕ объекты и заново добывается
// ссылка на текущий домен приложения.
// Теперь - дело техники. Надо загрузить и выполнить сборку.
// Делали. Умеем!
AppDomain currentAppDomain = Thread.GetDomain();
AssemblyGenerator assmGenerator = new AssemblyGenerator();
assmGenerator.CreateAssm(currentAppDomain);
// Загружаем сборку.
Assembly assm = Assembly.Load(“DynamicAssm”);
// Объект класса Type для класса DynamicTest.
Type t = assm.GetType(“DynamicAssm.DynamicTest”);
// Создаётся объект класса DynamicTest и вызывается конструктор с параметрами.
object[] argsX = new object[1];
argsX[0] = “Yes, yes, yes-s-s-s!”;
object obj = Activator.CreateInstance(t, argsX);
MethodInfo mi;
// «От имени» объекта-представителя класса DynamicTest
// вызывается метод ShowMessageString.
mi = t.GetMethod(“ShowMessageString”);
mi.Invoke(obj,null);
// «От имени» объекта-представителя класса DynamicTest
// вызывается метод GetMessageString.
// Этот метод возвращает строку, которая перехватывается
// и выводится в окне консольного приложения.
mi = t.GetMethod(“GetMessageString”);
//!!!//mi.Invoke(obj,null);//Этот метод не вызывается. Криво объявился? //
}
}
}