C# 基于类型的简单注入器条件注册

C# 基于类型的简单注入器条件注册,c#,dependency-injection,ioc-container,simple-injector,C#,Dependency Injection,Ioc Container,Simple Injector,我正在使用MediatR执行我的请求。在具体的处理程序中,我的要求是根据具体情况对一个或多个对象实例执行命令 让我们做一个简单的例子。假设请求是为移动服务客户执行补货。该要求规定,如果客户激活了多个服务,则必须对每个服务进行加满 当处理程序运行它时,首先加载客户服务 var services = context.Services.Where(c => c.CustomerId == customerId); foreach ( var service in services ) {

我正在使用MediatR执行我的请求。在具体的处理程序中,我的要求是根据具体情况对一个或多个对象实例执行命令

让我们做一个简单的例子。假设请求是为移动服务客户执行补货。该要求规定,如果客户激活了多个服务,则必须对每个服务进行加满

当处理程序运行它时,首先加载客户服务

var services = context.Services.Where(c => c.CustomerId == customerId);
foreach ( var service in services ) {
   //Do the topup
}
为了处理补货,我用命令模式实现了它。所以我有下面的模型

其中,调用程序正是MediatR处理程序实例。这是我的接收器接口

internal interface IReceiver<TRequest, TResponse>
    where TRequest : DefaultRequest
    where TResponse : DefaultResponse
{
        TResponse Apply( TRequest request );

        bool SupportsCommand( Type commandType );
}
内部接口IReceiver
其中TRequest:DefaultRequest
其中t响应:DefaultResponse
{
响应申请(请求请求);
bool支持命令(类型commandType);
}
还有一些基于网络元素品牌的不同实现(诺基亚、爱立信等)

内部抽象类BaseNokiaReceiver
:i接收器
其中TRequest:DefaultRequest
其中t响应:DefaultResponse
{
公共BaseNokiaReceiver(ILogger记录器、DataContext上下文、服务)
:base(记录器、上下文、服务){
}
公开摘要响应申请(TRequest请求);
}
和一个具体的

internal class NokiaDataTrafficReceiver : BaseNokiaReceiver<TopupRequest, TopupResponse>
{
    public NokiaDataTrafficReceiver(ILogger logger, DataContext context, Service service) 
        : base(logger, context, service) {
    }

    public override TopupResponse Apply( TopupRequest request ) {
        //[...] Application code
    }
}
内部类NokiaDataTrafficReceiver:BaseNokiaReceiver
{
公用诺基亚数据流量接收器(ILogger记录器、数据上下文、服务)
:base(记录器、上下文、服务){
}
公共覆盖TopupResponse应用(TopupRequest请求){
//[…]应用程序代码
}
}
由于一个客户可以在其帐户上启用多个服务,因此我必须有多个接收者使用一个命令类,例如

internal abstract class AbstractCommand<TRequest, TResponse> 
    : ICommand<TRequest, TResponse>
    where TRequest : DefaultRequest
    where TResponse : DefaultResponse
{
    protected IReceiver<TRequest, TResponse> _receiver;

    public AbstractCommand( IReceiver<TRequest, TResponse> receiver ) {
        _receiver = receiver;
    }

    public abstract Task<TResponse> Apply( TRequest request );
}
内部抽象类抽象命令
:i命令
其中TRequest:DefaultRequest
其中t响应:DefaultResponse
{
受保护的IReceiver\u接收器;
公共抽象命令(IReceiver接收器){
_接收器=接收器;
}
公共抽象任务应用(TRequest请求);
}

内部类重新加载:AbstractCommand
{
公共重新加载(IReceiver接收器):基本(接收器){
}
公共异步覆盖任务应用(TopupRequest请求){
var响应=_receiver.Apply(请求);
返回等待任务。FromResult(响应);
}
}
然后,处理程序实现变成如下所示

var services = context.Services.Where( c => c.CustomerId = customerId );
foreach ( var service in services ) {
    IReceiver<TopupRequest, TopupResponse> receiver = null;
    if ( service is VoiceService ) {
        receiver = new VoiceAccountReceiver();
    }
    else if ( service is DataService ) {
        receiver = new DataTrafficReceiver();
    }
    Reload command = new Reload( receiver );
    var result = command.Apply( input );
}
var services=context.services.Where(c=>c.CustomerId=CustomerId);
foreach(服务中的var服务){
i接收器=空;
如果(服务是语音服务){
receiver=新的VoiceAccountReceiver();
}
else if(服务是数据服务){
receiver=新的DataTrafficReceiver();
}
重新加载命令=新的重新加载(接收器);
var结果=命令。应用(输入);
}
每个接收器都会进行一次特定的加满

实际上,接收器的实例化是在代码中进行的,我想以一种可以使用DI容器的方式对其进行更改

通过使用伪代码,我想注册一个严格绑定到类型的接收方实例,例如

container.Register<IReceiver<TopupRequest, TopupResponse>, VoiceAccountReceiver>()
    .WhenParameterofType<VoiceService>();
container.Register<IReceiver<TopupRequest, TopupResponse>, DataTrafficReceiver>()
    .WhenParameterofType<DataService>();
container.Register()
.WhenParameterofType();
container.Register()
.WhenParameterofType();
因此,在运行时使用

container.GetInstance<IReceiver<TopupRequest, TopupResponse>>( typeof(service) );
container.GetInstance(typeof(service));

在我看来,您缺少一些类型信息,这些信息允许您在编译时区分不同的操作。这似乎很明显,因为您正在
VoiceService
DataService
上添加类型检查

因此,您可以尝试将该类型信息添加到
IReceiver
抽象中。例如:

interface IReceiver<TRequest, TResponse, TService> { }
var services = context.Services.Where(c => c.CustomerId == customerId);
foreach ( var service in services ) {
    var result = this.receiverMediator.Apply(input, service);
}
这允许根据其可用类型信息解析正确的接收器。最好,处理程序应该依赖于某种中介抽象。中介器实现将负责回调容器以解析正确的类型

例如:

interface IReceiver<TRequest, TResponse, TService> { }
var services = context.Services.Where(c => c.CustomerId == customerId);
foreach ( var service in services ) {
    var result = this.receiverMediator.Apply(input, service);
}
您的
iReceiveMediator
可以定义如下:

class VoiceAccountReceiver : IReceiver<TopupRequest, TopupResponse, VoiceService>
interface IReceiverMediator
{
    TResponse Apply<TRequest, TService>(TRequest input, object service)
        where TRequest : IRequest<TResponse>;
}
class SimpleInjectorReceiverMediator : IReceiverMediator
{
    private readonly Container container;

    public SimpleInjectorReceiverMediator(Container container) {
        this.container = container;
    }

    public TResponse Apply<TRequest, TService>(TRequest input, object service)
        where TRequest : IRequest<TResponse>
    {
        Type receiverType =
            typeof(IReceiver<,,>).MakeGenericType(typeof(TRequest), typeof(TResponse), service.GetType());

        dynamic receiver = container.GetInstance(receiverType);

        return (TResponse)receiver.Action();
    }
}
container.Register(typeof(IReceiver<,,>), assemblies);
container.Register<IReceiverMediator>(new SimpleInjectorReceiverMediator(container));
接口iReceiveMediator
{
响应应用(TRequest输入,对象服务)
其中TRequest:IRequest;
}
简单的特定于喷油器的实现可定义如下:

class VoiceAccountReceiver : IReceiver<TopupRequest, TopupResponse, VoiceService>
interface IReceiverMediator
{
    TResponse Apply<TRequest, TService>(TRequest input, object service)
        where TRequest : IRequest<TResponse>;
}
class SimpleInjectorReceiverMediator : IReceiverMediator
{
    private readonly Container container;

    public SimpleInjectorReceiverMediator(Container container) {
        this.container = container;
    }

    public TResponse Apply<TRequest, TService>(TRequest input, object service)
        where TRequest : IRequest<TResponse>
    {
        Type receiverType =
            typeof(IReceiver<,,>).MakeGenericType(typeof(TRequest), typeof(TResponse), service.GetType());

        dynamic receiver = container.GetInstance(receiverType);

        return (TResponse)receiver.Action();
    }
}
container.Register(typeof(IReceiver<,,>), assemblies);
container.Register<IReceiverMediator>(new SimpleInjectorReceiverMediator(container));
类SimpleInjectorReceiveMediator:IReceiveMediator
{
专用只读容器;
公共SimpleInjectorReceiverMediator(容器){
this.container=容器;
}
公共响应应用(TRequest输入、对象服务)
TRequest在哪里:IRequest
{
类型接收类型=
typeof(IReceiver).MakeGenericType(typeof(TRequest),typeof(TreResponse),service.GetType();
动态接收器=container.GetInstance(receiverType);
return(treresponse)receiver.Action();
}
}
这样就根本没有条件注册。您只需按如下方式批量注册所有接收器:

class VoiceAccountReceiver : IReceiver<TopupRequest, TopupResponse, VoiceService>
interface IReceiverMediator
{
    TResponse Apply<TRequest, TService>(TRequest input, object service)
        where TRequest : IRequest<TResponse>;
}
class SimpleInjectorReceiverMediator : IReceiverMediator
{
    private readonly Container container;

    public SimpleInjectorReceiverMediator(Container container) {
        this.container = container;
    }

    public TResponse Apply<TRequest, TService>(TRequest input, object service)
        where TRequest : IRequest<TResponse>
    {
        Type receiverType =
            typeof(IReceiver<,,>).MakeGenericType(typeof(TRequest), typeof(TResponse), service.GetType());

        dynamic receiver = container.GetInstance(receiverType);

        return (TResponse)receiver.Action();
    }
}
container.Register(typeof(IReceiver<,,>), assemblies);
container.Register<IReceiverMediator>(new SimpleInjectorReceiverMediator(container));
container.Register(typeof(IReceiver),assemblies);
Register(新的SimpleInjectorReceiverMediator(容器));

此问题缺少回答所需的许多重要信息。1.TypeA和接管人1之间的关系是什么?如果没有这样的描述,就无法定义条件。2.该示例不是一个可验证的最小完整示例,缺少一些上下文。3.什么是MyCommand?为什么要将依赖项注入其构造函数。4.总的来说,很难看出您正在尝试做什么,以及为什么在请求和处理程序之上需要接收器和命令。谢谢您的回答。我能理解你的问题。所有类的体系结构都很复杂,有很多