Jan 5 2009

Inversion of Control Containers

Category: C# | Patternsfossmo @ 05:35

Inversion of Control Container is easily put a hash table. A hash table that has a bunch of interfaces versus concrete types. There are a lot of these containers on the web. Some of the most used ones is Windsor, Autofac, Structuremap, Ninject and Unity. I will use Unity later in this post. To try to explain the concept of a IOC container, I will create a very simple one. The two main reasons I use IOC containers is to create loosely coupled applications and it helps me unit test my applications in an easy way. The core concept of dependency inversion principle, which a IOC container is based on, is that high level modules should not depend on the low level ones, but they should both depend on abstractions. The abstraction in these cases are interfaces or abstract-based classes. I recommend that you read my previous blog post about dependency injection if you don't know what dependency inversion principle is.

Let's create the IOC container.

  1:     public class MyIocContainer
  2:     {
  3:         private static readonly IDictionary<Type, object> objDictornary = new Dictionary<Type, object>();
  4: 
  5:         public static T Resolve<T>()
  6:         {
  7:             return (T)objDictornary[typeof(T)];
  8:         }
  9: 
 10:         public static void Register<T>(object objToRegister)
 11:         {
 12:             objDictornary.Add(typeof(T), objToRegister);
 13:         }
 14:     }

In 14 lines of code we have a very simple IOC container. If you want to start using a IOC container, but you can't add a third party library to your project, this could be an easy way to get some of the benefits a IOC container can give you. But, you are of course missing out on a lot of the features a "real" IOC container can provide. Some of the valuable features this container don't contain is allowing different styles of configuration (XML or annotations), lifetime management and autowiring. I will look into autowiring in a later post.

In the first post about DI and IOC containers, I ended the post with doing a poor man's dependency injection (line 11 in the code example below). I think the technical term for this is constructor initialization. This is done if you only want to expose only one of the parameters to the user of your library.

  1:           public Butler(IWeapon weapon, ICommunicate communicate)
  2: 
  3:           {
  4: 
  5:               _weapon = weapon;
  6: 
  7:               _communicate = communicate;
  8: 
  9:           }
 10: 
 11:           public Butler(IWeapon weapon): this(weapon, new Communicate())
 12: 
 13:           {}

Poor man's dependency injection works great, but it will give me a tight coupling against the Communication class. How can we get rid of this tight coupling? We can do as the code example below shows. In stead of creating a object in the constructor initializer I input "objects" from MyiocContainer as parameters.

  1:         public Butler():this(MyIocContainer.Resolve<IWeapon>(), MyIocContainer.Resolve<ICommunicate>())
  2:         {}
  3: 
  4:         //public Butler(IWeapon weapon): this(weapon, new Communicate())
  5:         //{}

We need to create a interface for the communicate class, of course. This was done in the post about dependency injection, but I repeate it here for convinience.

  1:     public interface ICommunicate
  2:     {
  3:         void Speak(string phrase);
  4:     }

Now we have a interface for the communicate class. Let's see how we can use MyiocContainer in the program.

  1:        class Program
  2:        {
  3:            static void Main(string[] args)
  4:            {
  5:                MyIocContainer.Register<IWeapon>(new Poison());
  6:                MyIocContainer.Register<ICommunicate>(new Communicate());
  7:    
  8:               Butler butler = new Butler();
  9:               butler.Kill("The young man");
 10:               butler.Speak("Drink this if you dare, Sir!");
 11:               Console.ReadKey();
 12:           }
 13:       }

The output after running the code above, looks like this.

image

Cool. This is nice. I now have a application where the dependencies is mostly based on interfaces. I can insert a new communication class or a weapon class as long as they implement the interfaces ICommunication and IWeapon. But, now we have a coupling against the IOC container we created. I need to create a abstraction. Doing this I can choose another container later. If I want to use Unity, Structuremap or another IOC container, it won't be a problem.  Lets create the abstraction using the static gateway pattern.

  1:     public static class MyContainerAbstractor
  2:     {
  3:         private static IResolver _resolver;
  4:         public static T Resolve<T>()
  5:         {
  6:             return _resolver.Resolve<T>();
  7:         }
  8: 
  9:         public static void Init(IResolver resolver)
 10:         {
 11:             _resolver = resolver;
 12:         }
 13:     }
 14: 
 15:     public interface IResolver
 16:     {
 17:         T Resolve<T>();
 18:     }

In the Butler class's constructor I do these changes.

  1: public Butler():this(ContainerAbstractor.Resolve<IWeapon>(), ContainerAbstractor.Resolve<ICommunicate>())

Then I need to change MyiocContainer to implement the interface I created and remove the static keywords.

  1:     public class MyIocContainer:IResolver
  2:     {
  3:         private readonly IDictionary<Type, object> objDictonary = new Dictionary<Type, object>();
  4: 

  5:         public T Resolve<T>()
  6:         {
  7:             return (T)objDictonary[typeof(T)];
  8:         }
  9: 
 10:         public void Register<T>(T obj)
 11:         {
 12:             objDictonary.Add(typeof(T), obj);
 13:         }
 14:     }

The main method will look like this after we have done the changes.

  1:     class Program
  2:     {
  3:         static void Main(string[] args)
  4:         {
  5:             MyIocContainer container = new MyIocContainer();
  6:             container.Register<IWeapon>(new Poison());
  7: 
  8:             container.Register<ICommunicate>(new Communicate());
  9:             container.Register<IButler>(new Butler());
 10:             
 11:             ContainerAbstractor.Init(container);
 12: 
 13:             IButler butler = new Butler();
 14:             butler.Speak("Drink this if you dare, Sir!");
 15:             butler.Kill("The young man");
 16:             Console.ReadKey();
 17:         }
 18:     }

Now we are using a abstraction against the IOC container. It's easy to use an other container if we want to do that. Let's create a abstraction against Unity.

  1:     public class MyUnityContainer:IResolver
  2:     {
  3:         readonly IUnityContainer myContainer = new UnityContainer();
  4: 
  5:         public T Resolve<T>()
  6:         {
  7:             return myContainer.Resolve<T>();
  8:         }
  9: 
 10:         public void Register<T>(object obj)
 11:         {
 12:             myContainer.RegisterInstance<T>((T)obj);
 13:         }
 14:     }

To run the program with the Unity container we can just replace one line of code in the main method. Replace

  1: MyIocContainer container = new MyIocContainer();

with

  1: MyUnityContainer container = new MyUnityContainer();

and we will get the same output as before

image

That's it for now. I recommend you to look into IOC containers if you already haven't done so.
In the next post I will show how to create a very simple autowiring mechanism in my home made IOC container.

Tags: , , ,

Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Comments

Comments are closed