c#-4.0 reflection.emit

c# 4.0 - Cómo crear un método en tiempo de ejecución usando Reflection.emit



c#-4.0 (1)

Estoy creando un objeto en tiempo de ejecución usando reflection emit. Creé con éxito los campos, las propiedades y los métodos get set. Ahora quiero agregar un método. En aras de la simplicidad, digamos que el método simplemente devuelve un número aleatorio. ¿Cómo defino el cuerpo del método?

EDITAR:

Sí, he estado buscando en la documentación de msdn junto con otras referencias y estoy empezando a pensar en esto. Veo cómo el ejemplo anterior está agregando y / o multiplicando, pero ¿qué ocurre si mi método está haciendo otras cosas? ¿Cómo puedo definir ese "material" Supongamos que estoy generando la clase a continuación dinámicamente, ¿cómo crearía el cuerpo del método GetDetails ()?

class TestClass { public string Name { get; set; } public int Size { get; set; } public TestClass() { } public TestClass(string Name, int Size) { this.Name = Name; this.Size = Size; } public string GetDetails() { string Details = "Name = " + this.Name + ", Size = " + this.Size.ToString(); return Details; } }


Utiliza un MethodBuilder para definir métodos. Para definir el cuerpo del método, llame a GetILGenerator () para obtener un ILGenerator , y luego llame a los métodos Emit para emitir instrucciones IL individuales. Hay un ejemplo en la documentación de MSDN para MethodBuilder, y puede encontrar otros ejemplos de cómo usar la emisión de reflejo en la página Usar emisión de reflexión :

public static void AddMethodDynamically(TypeBuilder myTypeBld, string mthdName, Type[] mthdParams, Type returnType, string mthdAction) { MethodBuilder myMthdBld = myTypeBld.DefineMethod( mthdName, MethodAttributes.Public | MethodAttributes.Static, returnType, mthdParams); ILGenerator ILout = myMthdBld.GetILGenerator(); int numParams = mthdParams.Length; for (byte x = 0; x < numParams; x++) { ILout.Emit(OpCodes.Ldarg_S, x); } if (numParams > 1) { for (int y = 0; y < (numParams - 1); y++) { switch (mthdAction) { case "A": ILout.Emit(OpCodes.Add); break; case "M": ILout.Emit(OpCodes.Mul); break; default: ILout.Emit(OpCodes.Add); break; } } } ILout.Emit(OpCodes.Ret); }

Parece que estás buscando recursos para escribir MSIL. Un recurso importante es la clase OpCodes , que tiene un miembro para cada instrucción IL. La documentación describe cómo funciona cada instrucción. Otro recurso importante es Ildasm o Reflector . Esto le permitirá ver el IL para el código compilado, que lo ayudará a comprender qué IL desea escribir. Ejecutando su GetDetailsMethod a través de Reflector y estableciendo el idioma en IL produce:

.method public hidebysig instance string GetDetails() cil managed { .maxstack 4 .locals init ( [0] string Details, [1] string CS$1$0000, [2] int32 CS$0$0001) L_0000: nop L_0001: ldstr "Name = " L_0006: ldarg.0 L_0007: call instance string ConsoleApplication1.TestClass::get_Name() L_000c: ldstr ", Size = " L_0011: ldarg.0 L_0012: call instance int32 ConsoleApplication1.TestClass::get_Size() L_0017: stloc.2 L_0018: ldloca.s CS$0$0001 L_001a: call instance string [mscorlib]System.Int32::ToString() L_001f: call string [mscorlib]System.String::Concat(string, string, string, string) L_0024: stloc.0 L_0025: ldloc.0 L_0026: stloc.1 L_0027: br.s L_0029 L_0029: ldloc.1 L_002a: ret }

Para generar un método así dinámicamente, deberá llamar a ILGenerator.Emit para cada instrucción:

ilGen.Emit(OpCodes.Nop); ilGen.Emit(OpCodes.Ldstr, "Name = "); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Call, nameProperty.GetGetMethod()); // etc..

También puede buscar introducciones a MSIL, como esta: Introducción al lenguaje de ensamblado IL .