morleyc
morleyc

Reputation: 2431

Invoking interface method, but System.Reflection.MethodBase set as System.Object

I am trying to invoke a generic interface method at runtime, however it seems when looking up the type info it is finding IDomainEventSubscriber rather than the correct type passed.

A runtime error is thrown: Object does not match target type.

Checking the values I see handlerInstance type is typeof(TestEventHandler), and methodInfo{System.Reflection.MethodBase} shows {Void HandleEvent(System.Object)}.

So it is being set as a method type of System.Object as opposed to the actual type (for example sake, TestEvent in the case we called Dispatch(new TestEvent());)

Is it possible to get the correct implementation so I can invoke the interface member at runtime?

public interface IDomainEventSubscriber<T>
{
    void HandleEvent(T domainEvent);
}

class TestEventHandler : IDomainEventSubscriber<TestEvent>
{
    public void HandleEvent(TestEvent domainEvent)
    {
    }
}

// some service that dispatches events
void Dispatch<T>(T eventToPublish) where T : class
{
    Type handlerType = map.GetHandlersForType(eventToPublish.GetType());
    // a valid object instance is returned from my IoC container
    object handlerInstance = this.ResolveHandler<T>(handlerType);

    // i can guarantee the instance implements IDomainEventSubscriber<T> where T
    // is the same type as eventToPublish

    Type typeInfo = typeof(IDomainEventSubscriber<T>);
    MethodInfo methodInfo = typeInfo.GetMethod("HandleEvent");

   // this line throws an error :(
    methodInfo.Invoke(handlerInstance, new object[] { eventToPublish });
}

Upvotes: 2

Views: 2040

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1500165

I don't think you need reflection at all. Given that you know the instance implements IDomainEventSubscriber<T>, why not just cast it to that?

// You could make ResolveHandler just return IDomainEventSubscriber<T> of course
var handler = (IDomainEventSubscriber<T>) ResolveHandler<T>(handlerType);

handler.HandleEvent(eventToPublish);

But your code actually seems to work okay for me, having extracted it into a short but complete program (below). The fact that your methodInfo has a parameter of type System.Object suggests that T is System.Object though, when presumably it should be TestEvent. So maybe the problem is just how your method is being called?

using System;
using System.Reflection;

public class TestEvent{}

public interface IDomainEventSubscriber<T>
{
    void HandleEvent(T domainEvent);
}

class TestEventHandler : IDomainEventSubscriber<TestEvent>
{
    public void HandleEvent(TestEvent domainEvent)
    {
        Console.WriteLine("Done");
    }
}

class Test
{
    static void Main(string[] args)
    {
        Dispatch<TestEvent>(new TestEvent(), typeof(TestEventHandler));
    }

    static void Dispatch<T>(T eventToPublish, Type handlerType)
    {
        object handlerInstance = Activator.CreateInstance(handlerType);
        Type typeInfo = typeof(IDomainEventSubscriber<T>);
        MethodInfo methodInfo = typeInfo.GetMethod("HandleEvent");       
        methodInfo.Invoke(handlerInstance, new object[] { eventToPublish });
    }
}

Upvotes: 4

Related Questions