Dependency Injection - what is it's value?

Demo Source: WindowsFormsApplication1.zip (476.45 kb)

It wasn't long ago that I was questioning the value of Dependency Injection (DI).  Now that I've used DI (Unity), I'll never go back to conventional programming.  

I provide a simple application to demonstrate it's value.  In my example I'm using Setter injection (you can also use Constructor).  If you are not familiar with these terms I would would recommend reviewing the documentation for the DI software you are using; I will be using Unity.

In any application there are many processing trees, below I have an A class which uses a B class which uses a C class - C is responsible for handling the processing.   We all know that once you develop a class it could potentially be reused by the team in any number of comparable trees going very deep and branching in many different directions.

In the constructor of my Form class below I have the following code to initialize my IFoo singleton:

        // Instantiate IFoo and set optional suffix
        IFoo myFoo = container.Resolve<IFoo>();
        myFoo.Suffix = "!!!";

What if my requirement has me in the "C" class below and I need an instance of IFoo?  Without Dependency Injection I would have to affect every module/assembly on the path to "C"; I would have to pass it through A and B. 

With DI, I simply have to set a Dependency attribute (or injection constructor) and I have an instance of it so that I can use it.  IFoo could just as easily been ILogger, IMyProcess or any other required implementation.   Likewise, if you create a NEW class, you can expose it to any branch in a DI tree by simply registering it in your configuration file.   More follows below the code.

using System;
using System.Windows.Forms;
using Microsoft.Practices.Unity;

public partial class Form1 : Form
{
    IUnityContainer container;
 

    public Form1()
    {
        InitializeComponent();
 

        // Register IFoo as a singleton
        container = new UnityContainer()
            .RegisterType<IFoo,Foo>(new ContainerControlledLifetimeManager());

        // Instantiate IFoo and set optional suffix
        IFoo myFoo = container.Resolve<IFoo>();
        myFoo.Suffix = "!!!";
    }
 

    private void button1_Click(object sender, EventArgs e)
    {
        container.Resolve<A>().DoSomething();               
    }
}


Below we have the IFoo, Foo, A, B and C classes

public interface IFoo {
    string Suffix { get; set; }
    void SayHello();
}

public class Foo : IFoo
{
    public string Suffix { get; set; }
    public void SayHello()
    {
        MessageBox.Show(string.Format("Hello World{0}",Suffix??":)"));
    }
}

public class A
{
    [Dependency]
    public B b { get; set; } 

    public void DoSomething(){
        b.DoSomething();
    }
}

public class B
{
    [Dependency]
    public C c { get; set; } 

    public void DoSomething() {
        c.DoSomething();
    }
}

public class C
{
    [Dependency]
    public IFoo myFoo { get; set; } 

    public void DoSomething(){
        myFoo.SayHello();
    }
}


Let's say in your large application you have IFoo in hundreds of classes and now you have to change Foo.   A DI application simply has to change the registration and the process is done, e.g.:

    container = new UnityContainer()
         .RegisterType<IFoo,Foo2>(new ContainerControlledLifetimeManager());


Now the entire application will be using the following class:

public class Foo2 : IFoo
{
    public string Suffix { get; set; }
    public void SayHello()
    {
        MessageBox.Show(
            string.Format("Hello USA{0}", Suffix??"=):)"));
    }
}

* The key is to use a DI container to resolve (instantiate) your classes.   During the "resolve" an object builder will interrogate the class to see if it has any Setter attributes or Injection constructor parameters to resolve; if it does it will build them which in turn interrogates it's child classes, so on and so on.  If you instantiate a class with New Foo() then you break the chain and it will no longer be able to resolve it's dependencies.

This is why in my form's constructor you'll find that I resolve IFoo as follows:

        // Instantiate IFoo and set optional suffix
        IFoo myFoo = container.Resolve<IFoo>();
        myFoo.Suffix = "!!!";

Source code: WindowsFormsApplication1.zip (476.45 kb)


Tags:
Categories:


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know