I have a generic interface ICommandHandler<>
that will have a number of implementations each for processing a specific implementation of ICommand
, e.g.:
public class CreateUserCommand : ICommand { ... }
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand> { ... }
When I'm given an ICommand
object I'm trying to dispatch it dynamically to the correct ICommandHandler
. At the moment I've used a pretty straightforward reflection approach with an Invoke
in my dispatcher class:
public void Dispatch<T>(T command) where T : ICommand
{
Type commandType = command.GetType();
Type handlerType = typeof(ICommandHandler<>).MakeGenericType(commandType);
object handler = IoC.Get(handlerType);
MethodInfo method = handlerType.GetMethod("Handle");
method.Invoke(handler, new object[] { command });
}
There are 2 problems with this approach. Firstly it uses slow reflection. Secondly if the method throws any kind of exception then it'll be wrapped in a TargetInvocationException
and I'll lose the stack trace if I re-throw it.
I worked out a way to make the call by creating a delegate and using DynamicInvoke
but this doesn't solve the problem with exceptions (and I'm not sure DynamicInvoke
is really any better than Invoke
):
public void Dispatch<T>(T command) where T : ICommand
{
Type commandType = command.GetType();
Type handlerType = typeof(ICommandHandler<>).MakeGenericType(commandType);
object handler = IoC.Get(handlerType);
MethodInfo method = handlerType.GetMethod("Handle");
Type actionType = typeof(Action<>).MakeGenericType(commandType);
Delegate action = Delegate.CreateDelegate(actionType, handler, method);
action.DynamicInvoke(command);
}
My question is, is there a better way to achieve what I'm trying to do? Preferably I could make a strongly-typed call instead of getting an object
and looking up the MethodInfo
. I assume that's not possible though because the type isn't know at compile time.
If that's not possible then an efficient solution that would throw the exception more 'natively' would be the next best option.
Edit: Updated code samples to clarify that I'm using IoC (Ninject) to create the ICommandHandler
at runtime, not Activator.CreateInstance()
as I first put. Included an example of how this would be used as requested:
var command = new CreateUserCommand() { Name = "Adam Rodger" };
var dispatcher = new CommandDispatcher();
dispatcher.Dispatch(command);
// this would send the message to CreateUserCommandHandler.Handle(command)
// dynamically and any exceptions would come back 'natively'
Edit 2: As suggested below, I can't cast the result of IoC.Get(handlerType)
to ICommandHandler<T>
because I get an InvalidCastException
at runtime. This is because at runtime T
is actually ICommand
, I assume because the command classes are arriving over WCF and somehow manage to lose their strong typing. The code that calls the dispatcher looks something like:
[ServiceContract]
public class CommandService
{
[OperationContract]
public void Execute(ICommand command) // no type information
{
var dispatcher = new CommandDispatcher(); // injected by IoC in real version
dispatcher.Dispatch(command);
}
}
See Question&Answers more detail:
os