C# 如何使用Simple Injector从中介发送调用

C# 如何使用Simple Injector从中介发送调用,c#,generics,dependency-injection,simple-injector,C#,Generics,Dependency Injection,Simple Injector,我有以下情况: public interface ICommand { } public interface ICommandHandler<TCommand> where TCommand : ICommand { void Handle(TCommand command); } public interface ISepsCommandHandler<TCommand> : ICommandHandler<TCommand> where

我有以下情况:

public interface ICommand { }

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

public interface ISepsCommandHandler<TCommand> : ICommandHandler<TCommand>
    where TCommand : ICommand
{
    event EventHandler<EntityExecutionLoggingEventArgs> UseCaseExecutionProcessing;
}

public sealed class CalculateNewAverageElectricEnergyProductionPriceCommandHandler
    : BaseCommandHandler,
    ISepsCommandHandler<CalculateNewAverageElectricEnergyProductionPriceCommand>
{ ... }

public sealed class CalculateCpiCommandHandler
    : BaseCommandHandler, ISepsCommandHandler<CalculateNewConsumerPriceIndexCommand>
{ ... }
问题:

我想将
ICommandHandler
的集合解析为
CqrsMediator
的构造函数。我试过各种方法

问题: 为什么这在SI中不起作用

var bla = GetAllInstances(typeof(ICommandHandler<ICommand>));
var bla=GetAllInstances(typeof(ICommandHandler));
我收到一条消息,它找不到
ICommandHandler
,但注册了
ICommandHandler
,尽管我在泛型中给出了一个约束,即TCommand只能是ICommand类型

有人能帮助构建和的中介模式吗

为什么这在SI中不起作用

var bla = GetAllInstances(typeof(ICommandHandler<ICommand>));
这与在.NET中不起作用的原因相同。只有当
ICommandHandler
接口定义为协变时,这才有效,但这是不可能的,因为
TCommand
是一个输入参数

让我们暂时从图片中删除DI容器。使用简单的旧C#代码,您希望实现以下目标:

ICommandHandler handler1=new Command1Handler();
ICommandHandler handler2=新的Command2Handler();
ICommandHandler handler3=新命令3 Handler();
IEnumerable handlers=new[]{handler1,handler2,handler3};
新的CqrsMediator(处理程序);
前面的代码段创建了三个新的命令处理程序:

  • Command1Handler
    实现
    ICommandHandler
  • Command2Handler
    实现
    ICommandHandler
  • Command3Handler
    实现
    ICommandHandler
因为要将它们注入
CqrsMediator
,所以需要将它们放入
ICommandHandler
类型的变量中。通过这种方式,您可以轻松构建一个数组(
ICommandHandler[]
),该数组可以注入到
CqrsMediator

但是,此代码不会编译。C#编译器将声明以下内容:

错误CS0266:无法将类型“Command1Handler”隐式转换为“ICommandHandler”。存在显式转换(是否缺少强制转换?)

这就是你问题的根源。例如,您的命令处理程序不能从
ICommandHandler
强制转换为
ICommandHandler
。要理解这一点,您需要了解协方差和逆变换。你可能想开始

要允许
ICommandHandler
可分配给
ICommandHandler
它要求
ICommandHandler
抽象是协变的:

  • 或者,如果将
    Send
    方法设置为泛型不是一个选项,则也可以在
    Send
    方法中使用反射来查找命令的正确类型:
  • 公共类CqrsMediator:ICqrsMediator
    {
    专用只读容器;
    公共CqrsMediator(Container Container)=>this.Container=Container;
    公共无效发送(TCommand命令)
    {
    var handlerType=typeof(ICommandHandler).MakeGenericType(command.GetType());
    动态处理程序=container.GetInstance(handlerType);
    返回handler.Handle((动态)命令);
    }
    }
    

    在这两种情况下,您都让
    CqrsMediator
    实现依赖于
    容器。这意味着实施成为基础设施的组成部分;它成为你生活的一部分。

    谢谢你,史蒂文!但是,是否可以将ICommandHandler集合注入CqrsMediator的构造函数,而不是容器或任何其他非容器的形式?如果您的
    CqrsMediator
    不是泛型的,您将如何注入
    TCommand
    ?你不能。您需要容器(或某种可以创建任意随机处理程序的工厂)来完成这项工作。
    public interface ICommandHandler<out TCommand> where TCommand : ICommand { ... }