I have a generic interface ICommandHandler<>
that will have a number of implementations each for processing a specific implementation of ICommand
Try this
dynamic handler=Activator.CreateInstance(handlerType);
try
{
handler.Handle((dynamic)command);
}
catch
{
// do whatever you want
}
Most DI containers (including Ninject) allow you to do something like this:
public void Dispatch<T>(T command) where T : ICommand
{
ICommandHandler<T> handler = IoC.Get<ICommandHandler<T>>();
handler.Handle(command);
}
If you don't know the type of command (in other words, if typeof(T) != command.GetType()
), using double-dispatch is the easiest way:
class SomeCommand : ICommand
{
// ...
public void Dispatch(IoC ioc)
{
var handler = ioc.Get<IHandle<SomeCommand>>();
handler.Handle(this);
}
}
but you could go with reflection if you find adding this code to all Commands distasteful.
Edit Here is a reflection-based version. You can (and should) cache the compiled delegate.
interface ICommand { }
interface IHandle<TCommand> where TCommand : ICommand
{
void Handle(TCommand command);
}
class CreateUserCommand : ICommand { }
class CreateUserHandler : IHandle<CreateUserCommand>
{
public void Handle(CreateUserCommand command)
{
Console.Write("hello");
}
}
[TestMethod]
public void build_expression()
{
object command = new CreateUserCommand();
object handler = new CreateUserHandler();
Action<object, object> dispatcher = BuildDispatcher(command.GetType());
dispatcher(handler, command);
}
private static Action<object, object> BuildDispatcher(Type commandType)
{
var handlerType = typeof(IHandle<>).MakeGenericType(commandType);
var handleMethod = handlerType.GetMethod("Handle");
var param1 = Expression.Parameter(typeof(object));
var param2 = Expression.Parameter(typeof(object));
var handler = Expression.ConvertChecked(param1, handlerType);
var command = Expression.ConvertChecked(param2, commandType);
var call = Expression.Call(handler, handleMethod, command);
var lambda = Expression.Lambda<Action<object, object>>(call, param1, param2);
return lambda.Compile();
}