在运行时将命令的不同实现注入命令

Mas*_*oud 13 c# structuremap dependency-injection multiple-instances

我的项目中有一个接口,有2个类实现它:

public interface IService
{
   int DoWork();
}

public class Service1:IService
{
    public int DoWork()
    {
       return 1;
    }
}  

public class Service2:IService
{
    public int DoWork()
    {
       return 2;
    }
}    
Run Code Online (Sandbox Code Playgroud)

我有一个依赖于它的命令处理程序IService:

public CommandHandler1:ICommandHandler<CommandParameter1>
{
     IService _service;  
     public CommandHandler1(IService service)
     {
          _service = service
     }  
     public void Handle()
     { 
          //do something
          _service.DoWork();
          //do something else 
     }
}

public interface ICommandHandler<TCommandParameter> 
                 where TCommandParameter :ICommandParameter
{
    void Handle(TCommandParameter parameter);
}
public interface ICommandParameter
{
}
Run Code Online (Sandbox Code Playgroud)

我想基于用户选择注入Service1Service2CommandHandler1.假设我有一个enum用户可以从中选择一个值:

public enum Services
{  
    Service_One,
    Service_Two 
}
Run Code Online (Sandbox Code Playgroud)

如果用户选择Service_One我想注入Service1我的命令处理程序,如果他选择Service_Two我想注入Service2命令处理程序.

我知道我可以使用命名实例,然后调用ObjectFactory.GetInstance<IService>().Named("Service1")例如,但有没有办法实现这个StructureMap并阻止使用Service Locator模式?

Ste*_*ven 9

使用运行时条件阻止构建对象图.应该修复对象图.使用运行时决策来确定通过对象图的路径.

你似乎在这里缺少的是一个抽象,它允许将请求委托给正确的IService实现; 我们称之为IServiceDispatcher:

interface IServiceDispatcher {
    int DoWork(Services data);
}

sealed class ServiceDispatcher : IServiceDispatcher {
    private readonly IService service1;
    private readonly IService service2;

    // NOTE: Feel free to inject the container here instead, as long as
    // this class is part of your composition root.
    public ServiceDispatcher(IService service1, IService service2) {
        this.service1 = service1;
        this.service2 = service2;
    }
    public int DoWork(Services data) {
        return this.GetService(data).DoWork();
    }

    private IService GetService(Services data) {
        switch (data) {
            case Services.Service_One: return this.service1;
            case Services.Service_Two: return this.service2;
            default: throw new InvalidEnumArgumentException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您CommandHandler1可以依靠IServiceDispatcher:

public CommandHandler1 : ICommandHandler<CommandParameter1> {
     private readonly IServiceDispatcher serviceDispatcher;
     public CommandHandler1(IServiceDispatcher serviceDispatcher) {
          this.serviceDispatcher = serviceDispatcher;
     }  

     public void Handle(CommandParameter1 commandParameter) { 
          //do something
          this.serviceDispatcher.DoWork(commandParameter.Service);
          //do something else 
     }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这IServiceDispatcher是一个非常难看的名称,从技术上描述了正在发生的事情.这是一个坏主意,因为界面应该在功能上描述你想要的东西.但是,由于您没有为您的问题提供任何特定于域的上下文,这是我能提出的最佳名称;-)