vexe
vexe

Reputation: 5615

Pass an Action<T> to a generic method via reflection?

I know there's similar questions to this but I still wasn't able to resolve my issue.

I have a EventManager static class, which is just a wrapper for EventManagerInternal, like so:

public static class EventManager
{
    public static void Subscribe<T>(Action<T> handler) where T : GameEvent
    {
        EventManagerInternal<T>.Subscribe(handler);
    }
    public static void Unsubscribe<T>(Action<T> handler) where T : GameEvent
    {
        EventManagerInternal<T>.Unsubscribe(handler);
    }
    public static void Raise<T>(T e) where T : GameEvent
    {
        EventManagerInternal<T>.Raise(e);
    }

    private static class EventManagerInternal<T> where T : GameEvent
    {
        private static Dictionary<Type, Action<T>> dic = new Dictionary<Type, Action<T>>();
        public static void Subscribe(Action<T> handler)
        {
            // sub code...
        }
        public static void Unsubscribe(Action<T> handler)
        {
            // unsub code...
        }
        public static void Raise(T e)
        {
            // raise code...
        }
    }
}

Example usage:

public class OnRename : GameEvent { }

public void OnRenameHandler(OnRename e) { }

EventManager.Subscribe<OnRename>(OnRenameHandler); // <-- the statement that I wanna generate via reflection

My question is: I want to generate the same thing (same usage example like ^) via reflection but I'm unable to. How to do it?

I managed to get the subscribe method right:

MethodInfo subscribe = typeof(EventManager).GetMethod("Subscribe").MakeGeneric(typeof(GameEvent)); // right?

But then how to invoke it passing in OnRenameHandler?

Knowing that I have a MethodInfo to OnRenameHandler

MethodInfo handler = typeof(SomeType).GetMethod("OnRenameHandler");

subscribe.Invoke(null, WHAT_TO_PASS_HERE?);

I tried Delegate.CreateDelegate but didn't get anywhere, I'm not sure it's the solution.

I've looked at several links, tried several things, but none worked.

Thanks for any help :)

Upvotes: 2

Views: 3920

Answers (1)

MarcinJuraszek
MarcinJuraszek

Reputation: 125610

Use Delegate.CreateDelegate static method to create delegate with a type known at runtime. First parameter sets the delegate type.

// get subscribe method info
var subscribe = typeof(EventManager).GetMethod("Subscribe")
                                    .MakeGenericMethod(typeof(OnRename));

// prepare delegate instance
var delegateType = typeof(Action<>).MakeGenericType(typeof(OnRename));
var methodInfo = typeof(TypeWithOnRenameHandlerMethod).GetMethod("OnRenameHandler");
var del = Delegate.CreateDelegate(delegateType, this, methodInfo);

// invoke subscribe method
subscribe.Invoke(null, new [] { del });

Replace this as second Delegate.CreateDelegate parameter if you need to call the method on other then current instance.

PS. I assumed that you really need to call Subscribe<OnRename>, not Subscribe<GameEvent>. Feel free to change it back if I'm wrong.

Upvotes: 9

Related Questions