Creando el método dinámicamente y ejecutándolo
Antecedentes
Quiero definir pocasstatic
métodos en C #, y generar código IL como conjunto de bytes, a partir de uno de estos métodos, seleccionados en tiempo de ejecución (en el cliente), y enviar el conjunto de bytes a través de la red a otra máquina (servidor) donde se debe ejecutar después de volver a generar el Código IL de la matriz de bytes.
Mi intento ( POC)
public static class Experiment
{
public static int Multiply(int a, int b)
{
Console.WriteLine("Arguments ({0}, {1})", a, b);
return a * b;
}
}
Y luego obtengo el código IL del cuerpo del método, como:
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
MethodInfo meth = typeof(Experiment).GetMethod("Multiply", flags);
byte[] il = meth.GetMethodBody().GetILAsByteArray();
Hasta ahora no creé nada dinámicamente. Pero tengo un código IL como conjunto de bytes, y quiero crear un ensamblaje, luego un módulo, luego un tipo, luego un método, todo de forma dinámica. Al crear el cuerpo del método del método creado dinámicamente, uso el código IL que obtuve usando la reflexión en el código anterior.
El código de generación de código es el siguiente:
AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName("MyDLL");
AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly(
aname,
AssemblyBuilderAccess.Run);
ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = modBuilder.DefineType("MyType",
TypeAttributes.Public | TypeAttributes.Class);
MethodBuilder mb = tb.DefineMethod("MyMethod",
MethodAttributes.Static | MethodAttributes.Public,
CallingConventions.Standard,
typeof(int), // Return type
new[] { typeof(int), typeof(int) }); // Parameter types
mb.DefineParameter(1, ParameterAttributes.None, "value1"); // Assign name
mb.DefineParameter(2, ParameterAttributes.None, "value2"); // Assign name
//using the IL code to generate the method body
mb.CreateMethodBody(il, il.Count());
Type realType = tb.CreateType();
var meth = realType.GetMethod("MyMethod");
try
{
object result = meth.Invoke(null, new object[] { 10, 9878 });
Console.WriteLine(result); //should print 98780 (i.e 10 * 9878)
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Pero en lugar de imprimir98780
en la ventana de salida, arroja una excepción que dice:
System.Reflection.TargetInvocationException: el destino de una invocación ha lanzado una excepción. ---> System.TypeLoadException: no se pudo cargar el tipo 'Invalid_Token.0x0100001E' desde el ensamblado 'MyDLL, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null'.
En MyType.MyMethod (Int32 value1, Int32 value2) [...]
Por favor, ayúdame a descubrir la causa del error y cómo solucionarlo.