Chris Pietschmann

husband, father, hacker, entrepreneur, futurist, innovator, autodidact

NAVIGATION - SEARCH

Design Patterns: Basics of Dependency Injection

Dependency Injection and Inversion of Control (IoC) have become popular buzz words in the .NET development world over the last couple years. However, It seems that not very many developers really know what they are. Like most design patterns they are rather simple in idea, but the various implementations can become complex to someone new to them. Also, it seems that these two are often considered that they must go together or even mistaken as the same thing. This prompted me to write up this short article to describe what Dependency Injection is.

What is Dependency Injection?

It is very common that you will instantiate an objects properties or internal members to some value other than null within the objects constructor; thus setting up the object for use when it is created. These values are considered “dependencies” since the object depends on them in order to function. The pattern at its most basic is just passing in these dependencies to the objects constructor instead of instantiating them directly within the objects constructor. By doing this you can change the objects dependencies without needing to modify, refactor or inherit the class. Also, dependency injection doesn’t rely on IoC and can be used without it.

Basic Implementation

Here’s a simple class that does not use dependency injection:

public class DataAccessLayer
{
    public DataAccessLayer()
    {
        // Instantiate the needed dependency
        this.Service = new DataService();
    }

    private IDataService Service { get; set; }

    public IQueryable<Person> GetOldPeople()
    {
        // A method that depends on the "Service" property
        return this.Service.People.Where(d => d.Age > 65);
    }
}

In the above example, you would need to modify the DataAccessLayer class in order to change the IDataService implementation that it uses. This makes Unit Testing the DataAccessLayer class extremly difficult since your tests will likely need to connect to a database in order to work.

Now, here’s the same class that uses Dependency Injection for the “Service” property:

public class DataAccessLayer
{
    public DataAccessLayer(IDataService service)
    {
        // use the injected dependency
        this.Service = service;
    }

    private IDataService Service { get; set; }

    public IQueryable<Person> GetOldPeople()
    {
        // a method that depends on the "Service" property
        return this.Service.People.Where(d => d.Age > 65);
    }
}

All that really changed when adding Dependency Injection was to make the constructor accept and require a reference to the desired IDataService implementation for the class to use. Now, in order to change the IDataService implementation to use you no longer need to modify the DataAccessLayer class itself.

Here’s an example of instantiating an instance of the DataAccessLayer class and passing in the desired dependency:

var myservice = new DataAccessLayer(new DataService());

Lastly, you can create a parameterless constructor to give the object a “default” IDataService to use if one is not specified. This can be handy for using at runtime, while the injection is used for unit testing. Here’s the DataAccessLayer class modified to include the parameterless constructor:

public class DataAccessLayer
{
    // parameterless constructor
    // using a "default" dependency
    public DataAccesLayer()
        : this(new DataService())
    { }

    // dependency injection constructor
    public DataAccessLayer(IDataService service)
    {
        // use the injected dependency
        this.Service = service;
    }

    private IDataService<Person> GetOldPeople()
    {
        // a method that depends on the "Service" property
        return this.Service.People.Where(d => d.Age > 65);
    }
}

How about Unit Testing?

When unit testing the above DataAccessLayer class you can create a simple IDataService class that contains all the test data in memory instead of requiring the database to execute the tests.

Here’s an example of a simple IDataService implementation that would contain all it’s data in memory for unit testing purposes:

public class MemeryDataService : IDataService
{
    public IQueryable<Person> People
    {
        return (
                 new List<Person>()
                 {
                     new Person { ID = 1, Age = 23, FirstName = "Bob", LastName = "Antonio" },
                     new Person { ID = 2, Age = 30, FirstName = "Sue", LastName = "Antonio" },
                     new Person { ID = 3, Age = 70, FirstName = "Steve", LastName = "Sanders" },
                 }
            ).AsQueryable();
    }
}

Conclusion

As you can see, Dependency Injection is really a simple design pattern to implement. It can be used without IoC (if desired) and doesn’t require any third party libraries or tools.

blog comments powered by Disqus