我有一个通用的接口ICommandHandler<>
将有一个号码的每个实施方式的用于处理特定实施ICommand
,例如:
public class CreateUserCommand : ICommand { ... }
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand> { ... }
当我给一个ICommand
对象我想要动态地分派到正确的ICommandHandler
。 目前我使用有一个非常简单的反射方法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");
method.Invoke(handler, new object[] { command });
}
有2个问题,这种方法。 首先,它采用慢反射。 其次,如果该方法抛出任何类型的异常然后它会被包裹在一个TargetInvocationException
,我会失去,如果我堆栈跟踪再次抛出它。
我摸索出了一种通过创建委托并使用拨打电话DynamicInvoke
但这并不解决异常问题(我不知道DynamicInvoke
真的比什么更好的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);
}
我的问题是,是否有更好的方式来实现我想要做什么? 最好我可以做一个强类型的呼叫,而不是得到一个object
和仰视MethodInfo
。 我认为这是不可能的,但因为该类型是不知道在编译时。
如果这是不可能的,那么这将引发异常更多的“原生”的有效解决方案将是一个最好的选择。
编辑 :更新的代码示例,以澄清,我使用的IoC(Ninject)创建ICommandHandler
在运行时,不Activator.CreateInstance()
是我第一次把。 包括如何按要求,这将使用一个例子:
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'
编辑2:如下建议,我不能投的结果IoC.Get(handlerType)
至ICommandHandler<T>
因为我得到一个InvalidCastException
在运行时。 这是因为在运行时T
实际上是ICommand
,我想是因为命令类到达了WCF并以某种方式设法失去了强类型。 调用调度程序的代码看起来是这样的:
[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);
}
}