Search code examples
c#dependency-injectionstructuremapmultiple-instances

Inject different implementations of an Interface to a command at runtime


I have an interface in my project that 2 classes implement it:

public interface IService
{
   int DoWork();
}

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

public class Service2:IService
{
    public int DoWork()
    {
       return 2;
    }
}    

I have a command handler that depends on IService too:

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
{
}

I want to inject Service1 or Service2 to my CommandHandler1 based on user selection. suppose that I have an enum and user could select a value from it:

public enum Services
{  
    Service_One,
    Service_Two 
}

If user selects Service_One I want inject Service1 to my command handler and If he selects Service_Two I want inject Service2 to the command handler.

I know that I can use named instances, and then call ObjectFactory.GetInstance<IService>().Named("Service1") for example, but Is there any way to implement this by StructureMap and prevent using Service Locator pattern?


Solution

  • Prevent building your object graphs using runtime conditions. Object graphs should be fixed. Use runtime decisions to determine the path through the object graph.

    What you seem to be missing here is an abstraction that allows delegating the request to the correct IService implementation; let's call it 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();
            }
        }
    }
    

    Now your CommandHandler1 can depend on 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 
        }
    }
    

    Do note that IServiceDispatcher is a really ugly name that technically describes what's going on. This is a bad idea, because the interface should functionally describe what you want. But since you didn't supply any domain-specific context to your question, this is the best name I can come up with ;-)