Básicamente, estoy aceptando un nombre de evento como una cadena, para obtener el EventInfo
. Luego, descubro el tipo de controlador de evento y tipo de argumento de evento usando reflection, creando un nuevo delegado de ese tipo (myEventHandler
) y conectándolo con el evento. Cuando alguna vez se invoque myEventHandler
, necesito abatir y pasar los argumentos al controlador.IL Emitir para invocar una instancia de delegado?
Mi código es el siguiente. El 'controlador' debe invocarse a través del myEventHandler
, siempre que se invoque 'd'. Necesito tener algún código de emisión de Reflexión allí donde puse ??? ¿Alguna idea?
EventHandler handler = delegate(object sender, EventArgs eventArgs)
{
//something will happen here
};
Type[] typeArgs = { typeof(object), derivedEventArgsType };
DynamicMethod myEventHandler = new DynamicMethod("", typeof(void), typeArgs);
var ilgen = myEventHandler.GetILGenerator();
//What should be the IL code here to
//cast derviedEventArgs to EventArgs and
//invoke the 'handler' above??????
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
Delegate d = dynamic.CreateDelegate(derviedEventHandlerType);
//addMethod is the add MethodInfo for an Event
addMethod.Invoke(target, new object[] { d });
Editar: Basándose en las observaciones a través del reflector.
El reflector código generado para un escenario codificado manualmente es
.method public hidebysig instance void <Main>b__1(object sender, class ConsoleApplication2.MyEventArgs e) cil managed
{
.maxstack 8
L_0000: nop
L_0001: ldarg.0
L_0002: ldfld class [mscorlib]System.EventHandler ConsoleApplication2.Program/<>c__DisplayClass3::handler
L_0007: ldarg.1
L_0008: ldarg.2
L_0009: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, class [mscorlib]System.EventArgs)
L_000e: nop
L_000f: ret
}
Y esto es lo que he intentado en base a eso.
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld,eh.GetType().GetField("handler"));
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Ldarg_2);
ilgen.EmitCall(OpCodes.Callvirt,eh.handler.Method,
new Type[]{ typeof(object), typeof(EventArgs) });
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);
Pero esto está causando un error de tiempo de ejecución:
'Calling convention must be varargs'
Probablemente me falta algo, necesita tener una mejor visión en IL.
El truco aquí siempre es simplemente escribir el código que desea en C# y usar el reflector/ILDASM para ver el IL. Supongo que una combinación de ld, castclass y callvirt –
Sí estuvo de acuerdo. Tomaré esa ruta, pero pensé que cualquier Reflejo emitir Ninjas en SO podría señalarlo rápidamente – amazedsaint
Mirando de nuevo, ¿dónde reside el "manejador"? relativo a los args? Estoy pensando que va a ser un dolor juntar los dos. Parece que la versión C# usa una clase de captura, pero su método dinámico en el momento es estático, por lo que no hay forma de empujar ningún estado ... –