At the time of this writing there are exactly 3.2 billion
different IOC containers available to .NET developers. In the vast majority of
common scenarios, they are functionally equivalent, while they do vary widely
in terms of performance and ease of configuration. For the purposes of this
article we are going to look only at the Unity container, which is available
from Microsoft Patterns and Practices. You can easily install it in your
application using the NuGet package
installer if you've installed that into Visual Studio 2010, or you can grab
Unity from its home on CodePlex and
add references the old fashioned way.
The best way to show how some code works is of course to
write some tests. In this case, we want to show that Unity by default will
return to us a new instance of a given type when we ask it for one, but that if
we provide it with the proper parameters, it will provide us with the same
instance again and again just like a Singleton-pattern class's Instance
property would.
The code in Listing 1 demonstrates these two tests in
practice. The first test shows that when we simply call the RegisterType method, resolving this type yields
separate new instances of the type. However, if we pass in a new ContainerControlledLifetimeManager() to the RegisterType() method, we then get the same
instance with each call to Resolve().
Listing 1 – Implementing Singleton Behavior with
Unity
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Tests
{
public interface IFoo
{
}
public class Foo : IFoo
{}
[TestClass]
public class UnityShould
{
private UnityContainer _container;
[TestInitialize]
public void Setup()
{
_container = new UnityContainer();
}
[TestMethod]
public void ReturnNewInstanceByDefault()
{
_container.RegisterType<IFoo, Foo>();
var firstInstance = _container.Resolve<IFoo>();
var secondInstance = _container.Resolve<IFoo>();
Assert.AreNotSame(firstInstance, secondInstance);
}
[TestMethod]
public void ReturnSameInstanceWhenConfiguredToDoSo()
{
_container.RegisterType<IFoo, Foo>
(new ContainerControlledLifetimeManager());
var firstInstance = _container.Resolve<IFoo>();
var secondInstance = _container.Resolve<IFoo>();
Assert.AreSame(firstInstance, secondInstance);
}
}
}
Running these tests reveals they are correct:
The great thing about using a container to manage the object
lifetimes is that it then becomes trivial to change, and simple to change the
behavior as needed (say, between production environment, unit tests,
integration tests, full system tests, etc.). And as you can see from the code
above, which includes 100% of the required to code make these tests pass,
getting started with an IOC container takes only a couple of lines of code, so
there's no good reason not to start using one in your application if you
haven't been for lack of exposure or comfort with them.