Comparing .Net IoC containers, part one: Microsoft Unity

Tags: IocContainer, IocComparison, DependencyInjection, DI, IoC, code, unity

Microsoft Unity is one of the simplest IoC containers to use. You only need a couple of lines of code to get going:

UnityContainer container = new UnityContainer();
container.RegisterType<IJellybeanDispenser, 
    VanillaJellybeanDispenser>();
SweetShop sweetShop = container.Resolve<SweetShop>();

The register and resolve syntax is straightforward.

Note that the types SweetShop and SweetVendingMachine have not been registered. Since they are concrete types which each have one public constructor, Unity can easily work out how to construct them - first new up all the needed dependencies, then plug these into the constructor.

When registering the same interface type twice, the second registration simply overwrites the first. A new instance is created each time, but this behaviour can be changed by using one of the provide "LifetimeManager" classes.

UnityContainer container = new UnityContainer();
 container.RegisterType<IJellybeanDispenser, 
    StrawberryJellybeanDispenser>(
    new ContainerControlledLifetimeManager());

Injecting simple types into a constructor is done with

UnityContainer container = new UnityContainer();
container.RegisterType<IJellybeanDispenser, 
    AnyJellybeanDispenser>(
    new InjectionConstructor(Jellybean.Lemon));

The InjectionConstructor object takes an array of objects, which are passed on when calling the AnyJellybeanDispenser constructor. There is potential for mismatches to not be discovered until runtime, but honestly this isn't much more so than already exists if a type mapping is omitted. Your tests should catch it.
A pre-built object instance can be registered easily as follows:

container.RegisterInstance(new AnyJellybeanDispenser(Jellybean.Cocoa));

The factory function support is also straightforward in Unity 2.0 - It was harder in previous versions of Unity):

UnityContainer container = new UnityContainer();
container.RegisterType<IJellybeanDispenser>
  new InjectionFactory(c => new AnyJellybeanDispenser(Jellybean.Orange)));

Injecting a trivial function is not that interesting, but using this to call out to your code can be quite useful where there is something more complex to achieve.

The code is maintined in a repository on GitHub. Here is the complete set of tests on Unity:

Unity: The code

namespace IoCComparison
{
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Practices.Unity;
    using NUnit.Framework;

    [TestFixture]
    public class UnityTestClass
    {
        [Test]
        public void CanMakeSweetShopWithVanillaJellybeans()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<SweetShop>();
            container.RegisterType<SweetVendingMachine>();
            container.RegisterType<IJellybeanDispenser, VanillaJellybeanDispenser>();

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Vanilla, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanMakeSweetShopWithVanillaJellybeansImplicitRegistration()
        {
            UnityContainer container = new UnityContainer();
            // Unity does not require explicit registrations for SweetShop and SweetVendingMachine
            // since there is no mapping, they are concrete types
            container.RegisterType<IJellybeanDispenser, VanillaJellybeanDispenser>();

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Vanilla, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanMakeSweetShopWithVanillaJellybeansRepeatRegister()
        {
            UnityContainer container = new UnityContainer();
            // duplicate registration just overwrites
            container.RegisterType<IJellybeanDispenser, VanillaJellybeanDispenser>();
            container.RegisterType<IJellybeanDispenser, StrawberryJellybeanDispenser>();
            container.RegisterType<IJellybeanDispenser, VanillaJellybeanDispenser>();

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Vanilla, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanMakeSweetShopWithStrawberryJellybeans()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IJellybeanDispenser, StrawberryJellybeanDispenser>();

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Strawberry, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void JellybeanDispenserHasNewInstanceEachTime()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IJellybeanDispenser, VanillaJellybeanDispenser>();

            SweetShop sweetShop = container.Resolve<SweetShop>();
            SweetShop sweetShop2 = container.Resolve<SweetShop>();

            Assert.IsFalse(ReferenceEquals(sweetShop, sweetShop2), "Root objects are equal");
            Assert.IsFalse(ReferenceEquals(sweetShop.SweetVendingMachine, sweetShop2.SweetVendingMachine), "Contained objects are equal");
            Assert.IsFalse(ReferenceEquals(sweetShop.SweetVendingMachine.JellybeanDispenser, sweetShop2.SweetVendingMachine.JellybeanDispenser), "services are equal");
        }

        [Test]
        public void CanMakeSingletonJellybeanDispenser()
        {            
            UnityContainer container = new UnityContainer();
            container.RegisterType<IJellybeanDispenser, StrawberryJellybeanDispenser>(new ContainerControlledLifetimeManager());

            SweetShop sweetShop = container.Resolve<SweetShop>();
            SweetShop sweetShop2 = container.Resolve<SweetShop>();

            Assert.IsFalse(ReferenceEquals(sweetShop, sweetShop2), "Root objects are equal");
            Assert.IsFalse(ReferenceEquals(sweetShop.SweetVendingMachine, sweetShop2.SweetVendingMachine), "Contained objects are equal");

            // should be same service
            Assert.IsTrue(ReferenceEquals(sweetShop.SweetVendingMachine.JellybeanDispenser, sweetShop2.SweetVendingMachine.JellybeanDispenser), "services are not equal");
        }

        [Test]
        public void CanMakeAniseedRootObject()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<SweetShop, AniseedSweetShop>();

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Aniseed, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanUseAnyJellybeanDispenser()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IJellybeanDispenser, AnyJellybeanDispenser>(new InjectionConstructor(Jellybean.Lemon));

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Lemon, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanUseConstructedObject()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterInstance<IJellybeanDispenser>(new AnyJellybeanDispenser(Jellybean.Cocoa));

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Cocoa, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanUseObjectFactory()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IJellybeanDispenser>(new InjectionFactory(c => new AnyJellybeanDispenser(Jellybean.Orange)));

            SweetShop sweetShop = container.Resolve<SweetShop>();

            Assert.AreEqual(Jellybean.Orange, sweetShop.DispenseJellyBean());
        }

        [Test]
        public void CanRegisterMultipleDispensers()
        {
            UnityContainer container = new UnityContainer();
            // different registrations have different names, otherwise will overwrite
            container.RegisterType<IJellybeanDispenser, VanillaJellybeanDispenser>("vanilla");
            container.RegisterType<IJellybeanDispenser, StrawberryJellybeanDispenser>("strawberry");

            IEnumerable<IJellybeanDispenser> dispensers = container.ResolveAll<IJellybeanDispenser>();

            Assert.IsNotNull(dispensers);
            Assert.AreEqual(2, dispensers.Count());
			
        }
    }
}
Add a Comment