Reputation: 2431
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
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