tags:

views:

1042

answers:

2

I need to generate an event handler based on an EventInfo object in runtime and call a method within that event handler. Something like the following:

public void RegisterAction(ActionData actionData, EventInfo eventInfo, 
    Control control)
{
    MethodInfo methodInfo = eventInfo.EventHandlerType.GetMethod("Invoke");

    List<Type> ps = new List<Type>();
    foreach (ParameterInfo info in methodInfo.GetParameters())
    {
        ps.Add(info.ParameterType);
    }

     DynamicMethod method = new DynamicMethod("Adapter",
                                              typeof (void),
                                              ps.ToArray(),
                                              GetType(), 
                                              true);

     ILGenerator generator = method.GetILGenerator();

     // Here I need to generate a method to do the following:
     // ExecuteAction(actionData);

     // Then I can use this runtime method as an event handler and
     // bind it to the control
     Delegate proxy = method.CreateDelegate(eventInfo.EventHandlerType, this);

     eventInfo.AddEventHandler(control, proxy);
}

I need help in generating the IL code for the commented part.

+1  A: 

I'm guessing you want to make a delegate from the MethodInfo of your event...

If so, here is an article describing how to go about this. The IL codes required are explained in that article.

Reed Copsey
+1  A: 
public void RegisterAction(ActionData actionData, EventInfo eventInfo, 
    Control control)
{
    MethodInfo methodInfo = eventInfo.EventHandlerType.GetMethod("Invoke");

    List<Type> ps = new List<Type>();
    ps.Add  (typeof (ActionData)) ;
    foreach (ParameterInfo info in methodInfo.GetParameters())
    {
        ps.Add(info.ParameterType);
    }

     DynamicMethod method = new DynamicMethod("Adapter",
                                              typeof (void),
                                              ps.ToArray(),
                                              GetType(), 
                                              true);

     // compatible signatures for ExecuteAction
     // (assuming you aren't interested in sender and eventArgs):
     // static void ExecuteAction (ActionData) ;
     // void ActionData.ExecuteAction () ;
     MethodInfo miExecuteAction = <...> ;
     ILGenerator generator = method.GetILGenerator();
     generator.Emit (OpCodes.Ldarg_0) ;
     generator.Emit (OpCodes.Call, miExecuteAction) ;
     generator.Emit (OpCodes.Ret) ;

     // if you want to pass this to ExecuteAction, 
     // you'll need to put it into actionData.
     Delegate proxy = method.CreateDelegate(eventInfo.EventHandlerType, actionData);

     eventInfo.AddEventHandler(control, proxy);
}

Edit: come to think of it, if all your events follow the (sender, args) pattern, you don't even need do mess with SRE:

public static void Execute<T> (ActionData data, object sender, T args)
    where T : EventArgs
{
    ExecuteAction (data) ;
}

public void RegisterAction (ActionData actionData, EventInfo eventInfo, 
    Control control)
{
    MethodInfo compatibleMethod = typeof (this).GetMethod ("Execute",
        BindingFlags.Static | BindingFlags.Public).MakeGenericMethod (
        eventInfo.EventHandlerType.GetMethod ("Invoke").GetParameters ()[1].ParameterType)) ;
    eventInfo.AddEventHandler (control, 
        Delegate.CreateDelegate (eventInfo.EventHandlerType, actionData,
        compatibleMethod)) ;
}
Anton Tykhyy
Neither of the proposed solutions work: The first one uses the first argument of the generated method and not the actionData from the RegisterAction method. The second one tries to generate an event with the wrong signature: ActionData shouldn't be one of the parameters of a method with (object, T)
Khash
The first parameter of the static method will be bound to the target object by the delegate constructor, so it should work OK (used the technique in my code), although I admit that I haven't compiled and run this particular code.
Anton Tykhyy
Read this http://msdn.microsoft.com/en-us/library/74x8f551.aspx
Anton Tykhyy
I've tried many different varieties of your code and every time it throws an "Error binding to target method." when it gets to CreateDelegate. The problem is it's not saying anything more as to why!
Khash
This here compiles and runs OK for me: http://pastebin.com/d5407c70e
Anton Tykhyy
Same for this one: http://pastebin.com/d6beca3f0.
Anton Tykhyy
Thanks Anton. The changes you made to the second solution made it work as well as a problem on my side: The ExecuteAction was on a generic class which made GetMethod return null. As for the SRE solution, it throws a CLR bad program exception when it is called. But I'm going to use the delegate one
Khash