我一直在使用与所描述的非常相似的模式在这篇优秀的文章中 http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91将命令和查询作为对象。我还使用 SimpleInjector 作为 DI 容器。
唯一显着的区别是控制器显式依赖于某些ICommandHandler<TCommand>
我希望控制器依赖于一个对象(一个Dispatcher
)这将需要ICommand
实例并解析该命令的正确处理程序。这将减少构造函数需要采用的参数数量,并使整个过程更容易使用。
So my Dispatcher
对象构造函数如下所示:
public CommandAndQueryDispatcher(IEnumerable<ICommandHandler> commandHandlers,
IEnumerable<IQueryHandler> queryHandlers)
{
}
我的 CommandHandler 接口如下所示:
public interface ICommandHandler<in TCommand> : ICommandHandler
where TCommand : ICommand
{
void Execute(TCommand command, ICommandAndQueryDispatcher dispatcher);
}
public interface ICommandHandler
{
void Execute(object command, ICommandAndQueryDispatcher dispatcher);
}
典型的命令处理程序如下所示:
public abstract class CommandHandlerBase<TCommand> : ICommandHandler<TCommand>
where TCommand : ICommand
{
public abstract void Execute(TCommand command, ICommandAndQueryDispatcher dispatcher);
public void Execute(object command, ICommandAndQueryDispatcher dispatcher)
{
Execute((TCommand) command, dispatcher);
}
}
internal class DeleteTeamCommandHandler : CommandHandlerBase<DeleteTeamCommand>
{
public DeleteTeamCommandHandler(){ }
public override void Execute(DeleteTeamCommand command,
ICommandAndQueryDispatcher dispatcher)
{
... functionality here...
}
}
然而,这种变化有一些影响,现在我想在我的命令和查询中添加一些装饰器,但我遇到了一些问题。
为了将所有命令和查询注入到Dispatcher
我让它们都有一个基础的、非通用的界面ICommandHandler
and IQueryHandler
,然后询问实际接收到的实例(这是通用的)以获取它们处理的命令类型以注册它们,以便我稍后可以根据给定命令的类型查找处理程序。
现在,当我尝试使用示例中所示的装饰器时,我似乎无法将任何内容注入到我的Dispatcher
,由于装饰实例被注册为泛型类型,因此不会被解析为基本类型ICommandHandler
实例。如果我尝试使装饰器成为非通用的,那么注入的实例没有任何通用类型参数,因此我无法找到其处理程序的命令类型。
我觉得我一定错过了一些相当简单的东西。
所以我的问题是
- 如何从容器中获取开放泛型类型的所有实例作为基本接口传递到我的
Dispatcher
?
OR
- 有没有更好的方法来实现调度程序功能,以便我的控制器可以不知道哪个处理程序将处理与 SimpleInjector 配合得更好的命令/查询?