Click here to Skip to main content
Click here to Skip to main content

Dependency Injection & IoC

, 26 Feb 2011
Rate this:
Please Sign up or sign in to vote.
Dependency Injection & IoC

Well, after I introduced Inversion of Control with few simple examples in my previous post, I thought it would be nice to take this discussion further with more implementation of Dependency Injection Principles. Later, I would also take a look at some of the existing frameworks available with Microsoft Patterns and Practices which follow these well known principles.

If you remember my previous post on Inversion of control with interfaces, I have clearly stated that we could invert the control to some other module to make strong decoupling on one class with the other. In this post, I will first cover the basics of the design principle on Dependency Injection and later talk about DI containers.

Dependency Injection

If you know about traditional Design Patterns, you should already know few of the most used patterns called Factory. Factory pattern allows you to put your object creation into a special module called Factory. Thus your objects will be created just inside your factory classes. But is it worth putting all the object creation inside your factory classes? That means each of those classes will hold reference of all the objects that needed to be created. Let's see the code to show up what I am talking about:

public enum ProcessorType
{
    x86,
    x64
}
public class Computer
{
    public IntelProcessor GetProcessor(double speed, ProcessorType type, string version)
    {
        return new IntelProcessor { Speed = speed, Type = type, Version = version };
    }
}

public class IntelProcessor
{
    public string Version { get; set; }
    public ProcessorType Type { get; set; }

    public double Speed { get; set; }

    public string GetProcessorInfo()
    {
        return string.Format("{0} Ghz Processor for {1}, v{2}", 
			this.Speed, this.Type, this.Version);
    }

    public override string ToString()
    {
        return this.GetProcessorInfo();
    }
}

Here I have a class called Computer which creates an object of a Processor. Every processor has Version, Type and Speed properties in it and hence the object is constructed with these values. Therefore, following the creational principle, the method follows a Factory. Is it? No. There is a problem in the code.

Let's suppose I want to create another class named AMDProcessor. Now how would you write the code:

public class Computer
{
    public IProcessor GetProcessor(double speed, ProcessorType type, 
		string version, string brand)
    {
        IProcessor processor = null;
        switch(brand)
        {
            case "INTEL":
                processor = new IntelProcessor 
		{ Speed = speed, Type = type, Version = version };
                break;
            case "AMD":
                processor = new AMDProcessor 
		{ Speed = speed, Type = type, Version = version };
                break
        }

        return processor;
    }
}

Thus I have created one Interface named IProcessor and made each of the Processor types to implement the IProcessor interface. The brand string parameter coming from to the method GetProcessor identifies which type of processor class to construct. The IProcessor interface will look like:

interface IProcessor
{
    string Version { get; set; }
    double Speed { get; set; }
    ProcessorType Type { get; set; }

    string GetProcessorInfo();
}

But there still lies a problem. When we talk about the Computer class, it has strong coupling with the actual types namely AMDProcessor or IntelProcessor Types. Hence if you want to include any other processor, you need to change the code for Computer class and include its type and recompile the project. Hence, it makes it cumbersome and makes it almost impossible to maintain such classes and also those classes are not flexible enough to handle Runtime Types.

Dependency Injection solves the issue by putting the creation of object outside the scope of the container. So if I implement the same class using Dependency Injection, it would look like:

public enum ProcessorType
    {
        x86,
        x64
    }
    public class Computer
    {

        public IProcessor CurrentProcessor { get; set; }

        public Computer(IProcessor processor)
        {
            this.CurrentProcessor = processor;
        }
        public IProcessor GetProcessor()
        {
            return this.CurrentProcessor;
        }
    }

 public class IntelProcessor : IProcessor
    {
        public string Version { get; set; }
        public ProcessorType Type { get; set; }

        public double Speed { get; set; }

        public string GetProcessorInfo()
        {
            return string.Format("{0} Ghz Processor for {1}, v{2}", 
				this.Speed, this.Type, this.Version);
        }

        public override string ToString()
        {
            return this.GetProcessorInfo();
        }
    }

Here, we have modified the object creation of dependent object IProcessor outside the scope of Computer which is more generalized. Now, if we expose the interface IProcessor, it is free to take any form way later than when the Computer class is compiled.

So the object will be created outside the scope of the computer but will inject the external object into the computer.

IntelProcessor processor = new IntelProcessor 
	{ Speed = 1.2, Type = ProcessorType.x64, Version = "3.5.6" };
Computer computer = new Computer(processor);

Clearly in the above implementation, I have used Constructor based DI implementation, but you can easily modify it to use Getter/Setter method using the Default constructor followed by the assignment of CurrentProcessor property.

IntelProcessor processor = new IntelProcessor 
	{ Speed = 1.2, Type = ProcessorType.x64, Version = "3.5.6" };
Computer computer = new Computer();
computer.CurrentProcessor = processor;

Or even we use separate ServiceLocator class to get the object of IProcessor from an abstract implementation of a Locator method.

public class ServiceLocator
{ 
public static IProcessor GetProcessor()
    {
        //resolve available IProcessor
    }
}
Computer computer = new Computer();
computer.CurrentProcessor = ServiceLocator.GetProcessor();

The ServiceLocator class takes the responsibility of resolving the available runtime IProcessor object available.

Note: You should not confuse ServiceLocator with Factory implementation. ServiceLocator is used to Locate and for implementation rather than creating a fixed set of types like Factory.

DI Containers

While talking about DI, I have told you that we need to inject one object within another. The DI container acts as a level of abstraction of the object creation. The Container actually handles object creation, association and configuration. Hence, if I have to write a container, I would:

  1. Create object of IProcessor (using actual implementation)
  2. Create an object of Computer
  3. Inject the object of IProcessor to Computer
  4. Configure Computer if any
public class ComputerContainer
{
    public Computer CurrentComputer { get; set; }
    public IProcessor CurrentProcessor { get; set; }

    public Computer GetComputer(IProcessor processor)
    {
        this.CurrentProcessor = processor;
        this.CurrentComputer = new Computer(processor);

        //Configure if any.
        return this.CurrentComputer;
    }
}

So you can think of a container as a higher level of abstraction, wrapping around all the objects that needs dependency injection and resolve each of them internally.

Conclusion

I am thinking of a separate post for implementation of Containers using Unity Framework. So, this is all about DI, I hope the post makes sense. Feel free to write your feedback, any addition to thoughts are welcome.

Thanks for reading the post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Abhishek Sur
Architect
India India
Did you like his post?
 
Oh, lets go a bit further to know him better.
Visit his Website : www.abhisheksur.com to know more about Abhishek.
 
Abhishek also authored a book on .NET 4.5 Features and recommends you to read it, you will learn a lot from it.
http://bit.ly/EXPERTCookBook
 
Basically he is from India, who loves to explore the .NET world. He loves to code and in his leisure you always find him talking about technical stuffs.
 
Presently he is working in WPF, a new foundation to UI development, but mostly he likes to work on architecture and business classes. ASP.NET is one of his strength as well.
Have any problem? Write to him in his Forum.
 
You can also mail him directly to abhi2434@yahoo.com
 
Want a Coder like him for your project?
Drop him a mail to contact@abhisheksur.com
 
Visit His Blog

Dotnet Tricks and Tips



Dont forget to vote or share your comments about his Writing
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralMy Vote of 5 PinmemberRaviRanjankr28-Feb-11 17:34 
GeneralMy vote of 5 PinmvpKunal_Chowdhury28-Feb-11 0:07 
GeneralMy vote of 5 PinmvpAbhijit Jana27-Feb-11 23:14 
Great Explanation Abhishek. Liked it !
Generalgood Pinmemberparrotfish2927-Feb-11 1:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140718.1 | Last Updated 27 Feb 2011
Article Copyright 2011 by Abhishek Sur
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid