15

I've been learning IoC, Dependency Injection etc. and enjoying the process. The benefits of decoupling and programming to interfaces are, to me, a no-brainer.

However, I really don't like binding myself to a specific framework like Unity or Autofac or Windsor - because I'm still learning and haven't yet decided which is best for my purposes.

So, how can I wrap around something like Unity so I could easily swap in Windsor at a later date? (or whatever). And don't you dare say use another one to inject the first one ;)

Thanks!

R.

P.s. I tagged Unity as that's my current personal preference (I just lurve Entlib).

5 Answers 5

19

You can certainly try making an abstraction from the container by declaring an IContainer with say Resolve and Register. I did that a couple of times. Then you would go ahead and implement a Container : IContainer and encapsulate an actual IoC container with your abstraction. I tried that with Unity and Castle Windsor.

But hey, soon I realised that this was really an over-engineering. I then understood that I tried to abstract from abstraction, yet to build another abstraction. This could be fine to learn the concept, but it was a real pain in the neck in a real project. I would highly recommend against an abstraction from IoC container. If you correctly use DI principle it will be fairly easy to change your container anyways.

The code looks overcomplicated, like

//I did this mess with Service Locator
var t = ContainerService.Instance.Resolve<IMyType>();
//others could go further with same Service Locator
var t = IoCFactory.Instance.CurrentContainer.Resolve<IMyType>();

//better way, use --> IoC and DI <--
//when a program starts, or a new instance of the context created
var t = Container.Resolve<IMyType>() //this lives at the bottom of the stack
//and then you just pass IMyType to the constructor of other types    
//you don't need to call Resolve again in the logical cycle

See this post by Ayende.

Yes, they abstracted the Inversion of Control Container. I think that if you need to do that, it is pretty clear that you don’t really get what IoC is all about.

3
  • You're quite right, this is for learning requirements. Once I settle on my container de jour, I'd be happy. But when you are learning and having to rewrite apps to cater for another container because the example on a blog is using x instead of y, well it gets to you after a while. I thought it'd be nice to have my own example and just figure out a way to easily swap out whatever container a blog was using to illustrate a particular concept.
    – Richard
    Commented Jan 5, 2012 at 23:25
  • I agree, this is overkill. A decent IoC container should have plenty of room for configuration so that you don't have to pollute your code with references to the container. If abstracting the container is the only way to make it work, then I'd say you're using a poor IoC container.
    – FMM
    Commented Jan 5, 2012 at 23:29
  • 4
    @Richard the point is there should only be a handful of classes even in the most complicated of projects that actively references the container. Everything else should have its dependencies injected into it. Thus there is no point abstracting it. Commented Jan 6, 2012 at 1:38
18

Use constructor injection to communicate what dependencies a class needs. Every container you listed supports it.

Sometimes a piece of code cannot achieve complete container independence, but these cases should be a very small part of your codebase.

0
10

A DI Container should only be referenced from the Composition Root. All other modules should have no reference to the container.

-Mark Seemann (author of Dependency Injection in .NET)

In other words, you should only need to change one class if you change DI containers.

Constructor injection is normally the right way to go, as others have mentioned. You can inject factory interfaces or Func<T> delegates if you need to create objects on the fly.

I'd also suggest avoiding XML configuration whenever possible.

0
4

As some other folks have mentioned, prefer constructor injection. This will solve many of your problems.

If your classes have direct dependencies on the IoC container itself, it tends to be a variant of using the service locator (anti-)pattern. In this particular case, isolate which types are being resolved via the service locator, and abstract that dynamic resolution with a factory interface. So, for instance, replace this:

public class Foo
{
    private MyIoCContainer _container;

    public Foo(MyIoCContainer container)
    {
        this._container = container;
    }


    public void DoSomething()
    {
        // have to do this at runtime for whatever reason
        var myObj = this._container.Resolve<ISomeType>();

        myObj.DoSomething();
        myObj.DoSomethingElse();
    }
}

with this:

public class Foo
{
    private IObjFactory _provider;

    public Foo(IObjFactory _provider)
    {
        this._provider = provider;
    }


    public void DoSomething()
    {
        var myObj = _provider.GetObj();

        myObj.DoSomething();
        myObj.DoSomethingElse();
    }
}

public interface IObjFactory
{
    ISomeType GetObj();
}

Now, you have an IObjFactory that can encapsulate the dynamic, runtime nature of constructing objects that implement ISomeType. If you are constructing many different types of object from the container/service locator, then you should have at least as many *Factory interfaces (in accordance with the Interface Segregation Principle).

3

Check out the Common Service Locator library (github). (Previously located on CodePlex).

2
  • 6
    imho, CSL is really only useful when building a component that will get used across multiple disparate projects that themselves might choose to use different IoC libraries. Using CSL oneself in their single line-of-business app, for example, is overkill. It adds a lot in dependency management and provides only a very narrow interface that could just as simply be specific in a core infrastructure lib of the app itself. Commented Jan 5, 2012 at 22:58
  • 3
    As one of the designers of CSL, I firmly endorse the above comment. CSL is intended for library authors who want a container, but don't want to force the library's choice of container on the app. Commented Jan 6, 2012 at 19:31

Not the answer you're looking for? Browse other questions tagged or ask your own question.