The first Commandment: Thou shalt not reference the IoC container!
I recently received a very nice email asking about one of my ‘10 Advanced Windsor Tricks’ posts where I’d stated, without really backing it up:
“Without this trick you would have to reference the container itself, which is an IoC anti-pattern of epic proportions.”
So why is referencing the IoC container an anti-pattern?
The hint is the name 'Inversion of Control'. IoC a is core principle of OO design, the idea being that you don't depend on concrete implementations, but on abstractions (in our case, interfaces). We want to build our software like Lego, out of independent components, that supply to their environment all the information about what they need to work. That information is described in interfaces. When we have a service like this:
public class MyService : ISomeService
{
public MyService(ISomeDependecy someDependency) {
}
}
… it's telling us two things, firstly that it supplies a service described by the ISomeService interface, that is, anywhere where an ISomeService is required, MyService can be supplied. The second thing it tells us is that it requires ISomeDependency to work. It doesn't care how that's implemented, just that whatever is supplied obeys that contract.
The important point here is that MyService is described entirely in terms of it’s own domain. Inversion of Control is a principle not a technology. We don’t need a container at this stage.
Now if I'm referencing a container I've lost that information:
public class MyService: ISomeService
{
public MyService() {
var someDependency = StaticContainer.Resolve<ISomeDependency>();
}
}
You might argue that the container is what it needs to in order to function, but we're really lying here, we could be using any dependency internally and it's not communicated to the outside world. Rather than describing our component in terms of its own domain, we’re polluting it with infrastructure concerns (the container).
By doing this you are making your life harder than it needs to be. Say I want to write a unit test for MyService, I now have to mock IContainer and get it to pass some mock of ISomeDependency, it's twice as much work. So not only have I lost information, I've made my own life as a developer harder.
But the most important message that this kind of code is carrying, is that the author has failed to grasp the real genius of IoC containers. I’ll try an example:
Say I have these components:
class Component1 : IComponent1
{
Component1(IComponent2 component2) { ... }
}
class Component2 : IComponent2
{
Component2(IComponent3 component3) { ... }
}
class Component3 : IComponent3
They are all registered with my IoC container. Now when I resolve IComponent1 like this:
var component1 = container.Resolve<IComponent1>();
the container will first create an instance of Component3, then an instance of Component2 passing it the Component3 instance in its constructor. Then finally it will create an instance of Component3 passing the Component2 instance to its constructor which it returns to the caller.
Deep inside our infrastructure, there is a single call to the container to get the root object of our application (our core application class if you will), all the cascading dependencies from that root object are discovered, constructed and supplied by the container. That's the magic of IoC containers, they glue our application together, but you never see them except for that initial, single resolve call.
So referencing the container itself is an anti-pattern of epic proportions, because it means you’ve failed to understand what an IoC container is. It's a bit like buying a tractor, hitching it up to a team of horses and attempting to plow a field with it.
0 comments