Search code examples
c#windows-phone

How to create a delegate with a dynamic parameter type?


I have a delegate object of type EventHandler<AsyncCompletedEventArgs> and I want to add this object to events of type EventHandler<T> where I know the type T always extends AsyncCompletedEventArgs. What I'm trying to do is kind of like this:

public static void AssignDelegate(this ICommunicationObject client, string eventName) 
{
    EventInfo eventInfo = client.GetType().GetEvent(eventName);
    EventHandler<AsyncCompletedEventArgs> eventHandler = (object o, AsyncCompletedEventArgs e) => 
    {
        // Some generic code that will be used as a handler to all events
    }    

    // I want be able to add the eventHandler to the eventInfo using the 
    // AddEventHandler method, but this does not seem possible since this 
    // event accepts delegates of type EventHandler<SomeClassThatExtendsAsyncCompletedEventArgs>
    // (It probably would if the EventHandler generic argument was contravariant)
    eventInfo.AddEventHander(client, eventHandler);
}

Is there other way to do this? Maybe changing at runtime the type of the parameter e?


Solution

  • You can do it via reflection:

    // your global handler, it can be regular method
    private static void GlobalEventHandler(object o, AsyncCompletedEventArgs e)
    {
        Console.WriteLine(e.GetType());
    }
    
    // your extension method
    public static void AssignDelegate(this object client, string eventName)
    {
        // get event
        EventInfo eventInfo = client.GetType().GetEvent(eventName);
        // get build handler method
        MethodInfo buildHandlerMethod = MethodInfo.GetCurrentMethod().DeclaringType.GetMethod("BuildHandler");
        // get type of arg; 
        // eventInfo.EventHandlerType is EventHandler<T>, where T: AsyncCompletedEventArgs, 
        // so we are interested in T
        Type argType = eventInfo.EventHandlerType.GetGenericArguments()[0];
    
        // add handler
        eventInfo.AddEventHandler(client, (Delegate)buildHandlerMethod.MakeGenericMethod(argType).Invoke(null, null));
    }
    
    // method which returns proper handler for event, 
    // it delegates invocation to GlobalEventHandler
    public static EventHandler<T> BuildHandler<T>() where T : AsyncCompletedEventArgs
    {
        return GlobalEventHandler;
    }