Search code examples
c#oopdesign-patternsinversion-of-controlservice-locator

IOC without Service Locator


Suppose I have 3 classes, Program, A (with dependencies D1 and D2) and B (with dependencies D3 and D4). Program initialises an IOC container and registers a bunch of types before creating an instance of A.

class Program
{
    static void Main(string[] args)
    {
        IOC ioc = new IOC();
        //register types

        A a = ioc.Resolve<A>();
    }
}

At some point later on, a needs to create an instance of B, injecting its two dependencies into the constructor.

Question: How should a resolve the dependencies of B? I have been led to believe that passing the IOC container around i.e. injecting it into A is the Service Locator pattern, which is bad. If B created C with its dependencies, B would also need to have the container injected, and the container would be littered throughout my code. This sounds like a testing nightmare. Using a global static doesn't sound much better.


Solution

  • It's actually simple. If A needs B, it should accept B as constructor argument:

    public class A
    {
        private readonly D1 d1;
        private readonly D2 d2;
        private readonly B b;
    
        public A(D1 d1, D2 d2, B b) {
            this.d1 = d1;
            this.d2 = d2;
            this.b = b;
        }
    }
    
    public class B
    {
        private readonly D3 d3;
        private readonly D4 d4;
        private readonly C c;
    
        public B(D3 d3, D4 d4, C c) {
            this.d3 = d3;
            this.d4 = d4;
            this.c = c;
        }
    }
    

    This way you build up object graphs recursively and you can get very deep object graphs, which is completely fine. This way you only need the container in the startup path of your application (a.k.a. the Composition Root).

    Whether or not A needs B 'later on', or just sometimes, or hardly ever is irrelevant. Building object graphs should be fast and whether or not B is created needlessly should therefore not be an issue.