C#泛型/ICommandHandler/ICommand设计

4

我需要设计一个命令/命令处理模块,但是在设计细节上遇到了困难。

我已经创建了一个(空的)接口:

public interface ICommand {}

这是由各种命令实现的,例如:

public interface TestCommand : ICommand {}

一个或多个 CommandHandlers 可以注册到特定的 ICommand 实现中。为了避免频繁强制类型转换,我已经建立了一个接口:

public interface ICommandHandler<in TCommand>
       where TCommand : ICommand
{
    void Handle(TCommand command);
}

目前为止一切都很好……问题出在命令分发系统上:命令处理程序应该由Autofac(或任何其他DI系统)注入,例如:

public CommandDispatcher (IEnumerable<ICommandHandler<ICommand>> commandHandlers)

如您所见,这是不可能的。`ICommandHandler`和`ICommandHandler`都没有从`ICommandHandler`继承,因此不能放入同一个IEnumerable中。
有什么建议可以以非问题方式设计它吗?
1个回答

3
通常您需要在调用它们之前解决它们。例如,在 Autofac 中。
class CommandDispatcher
{
    private readonly Autofac.IComponentContext context; // inject this

    public void Dispatch<TCommand>(TCommand command)
    {
        var handlers = context.Resolve<IEnumerable<ICommandHandler<TCommand>>>();
        foreach (var handler in handlers)
        {
            handler.Handle(command);
        }
    }

    public void ReflectionDispatch(ICommand command)
    {
        Action<CommandDispatcher, ICommand> action = BuildAction(command.GetType());
        // see link below for an idea of how to implement BuildAction

        action(this, command);
    }
}

如果你需要将方法签名更改为Dispatch(ICommand command),请查看此答案。你应该能够将其适应到你的情况中。

1
在我看来,无论何时都向容器注入依赖都是一种非常糟糕的做法。这应该只在顶层发生,对吧? - D.R.
你不需要在“任何地方”注入容器,只需在某些基础设施代码中注入即可。只要你的代码中引用容器的比例非常小,那就没问题了。有些人建议定义ICommandDispatcher,然后仅在组合根处创建一个AutofacCommandDispatcher,但我认为这是不必要的间接性 - 如果您切换DI容器,则需要相同数量的工作;唯一的优点是如果您不想在“业务逻辑”程序集中引用Autofac DLL。 - default.kramer
我们已经转换到这个解决方案,以避免不必要的引用,并使用了您链接帖子中的反射思想。谢谢。 - D.R.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接