Tuesday, March 13, 2012

Creating my own dependency injection system

This post is about creating my own dependency injection system.

Dependency injection allows us to inject dependencies at run-time instead of compile-time. I’m going to start with the simple version, which I’ll describe using the following requirements:

  1. I want to define a binding between an interface and a class using generics. Obviously the class must implement the interface.
    • This means that all dependencies must be known at compile-time. So for now I’m not going to include any run-time loaded types based on string values, or any other similar methods.
  2. I want to use fluent interfaces to define the binding.
  3. I want to be able to resolve an instance of an object by specifying the interface type.

Going from the list above I could come up with the following way to define a binding and to get an instance of an class:

   1: namespace MyDI_Tests {
   2:     public static class Test {
   3:         public static void DoTest() {
   4:             Factory.Bind<ITestObject>().To<TestObject>();
   5:             var test = Factory.GetInstance<ITestObject>();
   6:             // test should be of type TestObject
   7:         }
   8:     }
   9: }

In the text below, I will reference to the ITestObject type as the interface-type and the TestObject type as the class-type.

All right, lets make it happen. First we need a Factory class.

   1: namespace MyDI {
   2:     public static class Factory {
   3:         public static IBindingRule<TInterface> Bind<TInterface>() {
   4:             // TODO
   5:             throw new NotImplementedException();
   6:         }
   8:         public static TInterface GetInstance<TInterface>() {
   9:             // TODO
  10:             throw new NotImplementedException();
  11:         }
  12:     }
  13: }

We are also in need of an interface to define a binding rule. We’ll worry about the implementation later.

   1: namespace MyDI {
   2:     public interface IBindingRule<TInterface> {
   3:         void To<TClass>() where TClass : class, TInterface, new();
   4:     }
   5: }

And presto, now we can define binding rules in the factory. Let’s create a unittest. We need a dummy interface and class, and a unittest class.

   1: namespace MyDI_Tests {
   2:     interface ICommunicator {
   3:         void SendCommand(string command);
   4:     }
   6:     class WirelessCommunicator : ICommunicator {
   7:         public void SendCommand(string command) {
   8:             throw new System.NotImplementedException();
   9:         }
  10:     }
  11: }
   1: namespace MyDI_Tests {
   2:     [TestClass]
   3:     public class FactoryTests {
   4:         [TestMethod]
   5:         public void TestMethod1() {
   6:             Factory.Bind<ICommunicator>().To<WirelessCommunicator>();
   7:             var test = Factory.GetInstance<ICommunicator>();
   8:             Assert.IsNotNull(test);
   9:             Assert.AreEqual(typeof(WirelessCommunicator), test.GetType());
  10:         }
  11:     }
  12: }

Now we can run our unittest, and obviously it fails.


We need to create a binding rule class, and finish the factory class. To do that, we are also going to need another class, a class which will actually create an instance of an object. The reason for this is the following: When the Factory.Bind<TInterface>() method is called, an instance of the binding rule class is created. But the IBindingRule<TInterface>.To<TClass>() method specifies to which class-type the binding-rule should use. Therefore the binding rule cannot hold the class-type, and this is where the ‘instance creator’ comes into play. The instance creator class knows the interface-type, and the class-type, and therefore can return an object of the class-type.

I was struggling with the instance creator class at first, but once I figured out that the interface doesn’t know the class-type, and the class does know the class-type, things started to work out.

To reference the non-generic binding rules from the Factory a non-generic binding rule interface is necessary; the generic binding rule interface of course inherits this interface as well.

Lets create the binding rule class, the instance creator interface and class, and finish the factory class.

   1: namespace MyDI {
   2:     interface IInstanceCreator<TInterface> {
   3:         TInterface Create();
   4:     }
   5: }
   1: namespace MyDI {
   2:     class InstanceCreator<TInterface, TClass> : IInstanceCreator<TInterface>
   3:         where TClass : class, TInterface, new() {
   4:         public TInterface Create() {
   5:             return new TClass();
   6:         }
   7:     }
   8: }
   1: namespace MyDI {
   2:     public interface IBindingRule { }
   4:     public interface IBindingRule<TInterface> : IBindingRule {
   5:         void To<TClass>() where TClass : class, TInterface, new();
   6:     }
   7: }
   1: namespace MyDI {
   2:     class BindingRule<TInterface> : IBindingRule<TInterface> {
   3:         private IInstanceCreator<TInterface> _creator;
   5:         public void To<TClass>() where TClass : class, TInterface, new() {
   6:             _creator = new InstanceCreator<TInterface, TClass>();
   7:         }
   9:         public TInterface Create() {
  10:             if (_creator != null) {
  11:                 return _creator.Create();
  12:             }
  13:             throw new InvalidOperationException();
  14:         }
  15:     }
  16: }
   1: namespace MyDI {
   2:     public static class Factory {
   3:         public static IBindingRule<TInterface> Bind<TInterface>() {
   4:             throw new KeyNotFoundException();
   5:             if (!_bindingRules.ContainsKey(typeof(TInterface))) {
   6:                 var bindingRule = new BindingRule<TInterface>();
   7:                 _bindingRules.Add(typeof(TInterface), bindingRule);
   8:                 return bindingRule;
   9:             }
  10:             throw new InvalidOperationException();
  11:         }
  13:         private static readonly Dictionary<Type, IBindingRule> _bindingRules = new Dictionary<Type, IBindingRule>();
  15:         public static TInterface GetInstance<TInterface>() {
  16:             if (_bindingRules.ContainsKey(typeof(TInterface)) && _bindingRules[typeof(TInterface)] is BindingRule<TInterface>) {
  17:                 return ((BindingRule<TInterface>)_bindingRules[typeof(TInterface)]).Create();
  18:             }
  19:             throw new InvalidOperationException();
  20:         }
  21:     }
  22: }

So what is exactly happening here?

Interface IInstanceCreator<TInterface> This interface defines an instance creator. Generics-wise it only knows the interface-type, since the binding rule must hold a reference to the instance creator. It has a single method, the Create() method, which is meant to return an instance of an object which implements the interface-type.

Class InstanceCreator<TInterface, TClass> This class implements the IInstanceCreator<TInterface> interface, and therefore has a Create() method. This method can simple create a new object of the class-type using the parameterless constructor.

Interface IBindingRule This interface defines a non-generic binding rule. This is necessary for the factory to reference a collection of binding rules. Of course it could be a list of objects as well, but using this interface it is somewhat strongly typed.

Interface IBindingRule<TInterface> This interface defines a generic binding rule. This interface exposes a single method to define the binding, specifying the class-type using generics.

Class BindingRule<TInterface> This class implements the IBindingRule<TInterface> interface. It is actually very simple. When the To<TClass> method is called, an instance of the InstanceCreator class is created. When the Create method is called, the instance creator is used to create an instance of the class-type.

Class Factory This class provides public access to the binding rules by exposing two static methods. One is the Bind<TInterface> method which can be used to create a binding rule. The binding rule is stored in a private dictionary. The other method is the GetInstance<TInterface> method in which a binding rule is retrieved from the dictionary, and the Create-method is used to get an instance of the object.

Now we have a unittest that passes. Excellent!


Using the factory we can define a binding rule in one assembly, and get an instance of a class that normally wouldn’t be accessible (without using reflection or some other method). The following diagram shows what I mean.


In the core assembly an interface is defined, and in that same assembly we want to use it. But the implementation is done in the implementing assembly which we can´t reference, since that assembly references the core assembly. This is possible using the factory.

Please note that the code shown above is not yet thread-safe.

In the next post I will introduce the concept of the binding scope. With the binding scope we can specify if and how previously created objects are re-used. For example: a singleton-scope.

The code can be downloaded here.


  1. Great article

    We can also submit our .net related article links on http://www.dotnettechy.com to improve traffic.

    This website also have directory submission for .net related website / blog only

    1. Hi Micle,
      Thank you for your reply.
      I have no problem with a link to my article being submitted on your website. Can I do this myself, or do you have to do it?
      Kind regards,