Dependency injection

This article was originally published in VSJ, which is now part of Developer Fusion.
Object-oriented programming is hard. Even basic concepts, such as abstraction, encapsulation, polymorphism and inheritance, can take considerable time to master. Consequently, the “big four” listed above become the focus of most of the teaching effort. Which is a shame, given that the majority of our time is often spent dealing with issues such as test-driven development, maintenance and code reusability.

What is doubly ironic is that experienced OO developers actually spend considerable amounts of their lives working out how to avoid working directly with objects, instead preferring to use interface references. This article therefore discusses the reasoning behind, and the techniques involved, in working with a pattern that is widely adopted in modern enterprise-scale OO programming: Dependency Injection.

Our sample problem

Let’s begin by looking at a (deliberately) very simple example that highlights a common problem in OO programming – see Listing 1.

The common problem that this code highlights is simple: there is a 100% dependency between two concrete types. In this case, the SpellChecker cannot function without the presence of a dictionary object, and this naive implementation simply instantiates the dictionary as the SpellChecker object is constructed.

This approach causes a number of problems, including:

  • it is impossible to use the SpellChecker with other dictionary implementations,
  • it is impossible to deploy the SpellChecker without the FileBasedDictionary code,
  • it is harder to unit test the SpellChecker, and
  • whilst the implementation for the FileBasedDictionary class is not shown, there is no way for the client to alter which dictionary file it uses
In simple terms, the implementation closely couples the SpellChecker to the FileBasedDictionary; and for the reasons listed above this is a Bad Thing.

The remainder of this article therefore considers how you might fix this pattern of code.

Fix #1: Use interface-based programming

The first critical problem with the SpellChecker code is that it can only work with file-based dictionaries. This makes it worse than useless, but fortunately you can fix this in a flash by using standard interface-based (or abstract-base class) programming.

Listing 2 highlights a more appropriate implementation for the dictionary. While it has made it much easier to use different dictionary implementations in your code, there remains a lurking problem: the SpellChecker, as written, uses the new keyword to allocate the dictionary within the SpellChecker, and thus it is still coupled to the concrete type. Let’s examine how you might address this.

Option 1: Add more parameters
It is possible to fix the dependency just by modifying the SpellChecker.CheckStream() method so that it takes the dictionary implementation as an additional parameter, as shown below:

public bool CheckStream( StreamReader sr,
	ISpellingDictionary dictionary,
	out long offset, out List<String> alternatives )
{
	...
}
There can be negative side effects to this approach. For example, the number of parameters can become extreme, and you can end up with what is essentially non-OO programming. You might even be passing the SpellChecker between modules within a system, where it would be far more sensible for the SpellChecker object to be ready to operate, without requiring you to pass each module both a SpellChecker and a dictionary.

However, the core concept of having the caller pass in the implementation is precisely what Dependency Injection is all about. Briefly, Dependency Injection simply means that the client going to provide the object that has the dependency (SpellChecker in this example) with the object(s) on which it is dependent.

Let’s start with a form of Dependency Injection known as Constructor Injection.

Option 2: Constructor Injection
Listing 3 shows the use of Constructor Injection for the SpellChecker. Clearly, the client code that uses this new implementation of SpellChecker can be simple as that shown below:

SpellChecker sc = new SpellChecker(
	new GoogleApiDictionary());
sc.CheckStream( ... );

Option 3: Property injection
A common alternative to using Constructor Injection is to use Property Injection. In Property Injection (which is also known as Setter Injection), the object is constructed and then it is initialised for use by setting properties.

Listing 4 shows a modified version of the SpellChecker type that supports Property Injection.

Using this new version of the SpellChecker is as easy as ever, especially with the new C# 3.0 syntax:

SpellChecker sc = new SpellChecker()
	{ Dictionary =
		new FileBasedDictionary(
		@"C:\english.dic") };

Constructor vs. Property Injection

Which form of Dependency Injection should you favour in your designs?

My personal favourite, and that recommended by the various Inversion of Control container authors, is Constructor Injection. The reasoning is straightforward: upon completion of the constructor, the object is “good to go” and will be in a consistent state. It’s a little like buying a new car: you just want to hop in and drive the thing, not wait for a team of mechanics to build the car around you as you start it up. I also like the fact that one quick glance at the constructor tells me everything I need to set up for the object: it’s a single point of documentation!

However, Property Injection definitely has its place, as it has the potential to allow you to construct an object before configuring its dependencies later, including replacing them on the fly. The important thing to note about Property Injection is that the object might be in an inconsistent state: for example, you might attempt to use a SpellChecker that has not had its Dictionary property set.

There is also another downside to Constructor Injection: when you create deep inheritance hierarchies, you can end up with either large numbers of constructors, or constructors with large parameter lists, in order to ensure that all the base classes get their requisite dependencies set. If this starts to occur, you’ll need to either consider using Property Injection or perhaps refactor the code to make it less unpleasant.

There are other forms of Dependency Injection in use today, such as method injection and interface injection. As their names suggest, these involve setting the dependencies on the object by calling methods (or via interfaces). These techniques are less popular than Constructor and Property Injection, so I won’t waste space discussing them here.

By now, you should be thinking that Dependency Injection isn’t anything special, and certainly not too complicated. The benefits, on the other hand, are considerable. In the case of the SpellChecker, it has decoupled the SpellChecker from its dictionary implementations; allowed the client to specify which dictionary it wants to use; and allowed us to test the SpellChecker with test-specific dictionaries (without having to use a mocking engine to inject a set of mocked expectations). In fact, the refactored code is now a fairly representative example of the Gang of Four’s Strategy pattern, whereby the SpellChecker can use a different strategy for performing its spell checking work (more on the Strategy pattern), simply by altering the Dictionary property on the fly.

However, this flexibility comes at a cost that has to be borne by someone. That someone is the client code, which now has additional dependencies on the different dictionary implementations, rather than just the SpellChecker, and which has (potentially) additional complexity. In order to remove that complexity from the client code, you can hide it inside yet another type, often known as a Builder, which constructs the objects on your behalf. Of course, the problem with this approach is that you still have to tell the builder which implementation of ISpellingDictionary that you want it to work with.

Hmmph! Maybe this isn’t quite so easy after all, as all we seem to have achieved is to move the problem further up into the client.

new is not the only way

The key to breaking the impasse is that using new is not the only way to create objects. Alternatives are available in the shape of the Type and Activator classes, to name but two. For example, you could use either of the following snippets of code to create the original SpellChecker object from Listing 1.
SpellChecker sc;
// Either this ...
sc = Activator.CreateInstance("Demo", "Demo.SpellChecker")
	as SpellChecker;
// or this will do
Type t = Type.GetType("Demo.SpellChecker");
ConstructorInfo ci = t.GetConstructor(Type.EmptyTypes);
sc = ci.Invoke(null) as SpellChecker;
Note that “Demo” is the name of both the namespace and the assembly for this code!

I hope that your heart leapt the moment that you saw the type name appear as a string: you should be thinking that you could move the complexity away from your code and out into configuration. So let’s examine how you might implement a simple container that could retrieve objects, obviating the need for complex client code.

Implementing a Dependency Injection container

In an ideal world, it might be nice to be able to write code similar to the following in order to make a SpellChecker, complete with a dictionary:
Container c = new Container();
SpellChecker sc = c.GetObject<SpellChecker>();
...
sc.CheckStream( ... );
Clearly, the exciting player is the new, magical, Container type that somehow understands how to create a SpellChecker object and configure it with an implementation of ISpellingDictionary. This is the key to a decent Dependency Injection container (DI container): you ask it for an object, and it injects all the dependencies for you.

So what underpins this code? Most importantly in this discussion, the actual detailed implementation of the container is actually by-the-by. The majority of containers that are available today support both configuration-driven DI, as well as code-based type registration. Some (many) even support Dependency Injection based on attributed programming, whereby a type’s author will decorate a class similar to the following:

public class SpellChecker
{
	ISpellingDictionary dictionary;
	public SpellChecker( [CreateNew]
		ISpellingDictionary dic )
	{
		dictionary = dic;
	}
}
At run-time, the DI container can reflect over the type and inject a new object automatically.

To give you an idea behind the principles (and problems) of DI containers, I put together a simple container that uses .NET configuration files for its information. Listing 5 provides an example of the configuration file used by the simple DI container.

The fine detail of Listing 5 are relatively unimportant, but let me just take a minute to explain how the Container uses this file, as many DI containers work in a similar fashion. In response to the call to GetObject<T>(), it locates the matching <type> element. It then uses Activator.CreateInstance() to create the SpellChecker object. It then uses Property Injection to set the Dictionary property on the newly created SpellChecker. The configuration information provided here (namely, the isDependency="true" attribute) tells the container that it should automatically inject the default implementation of ISpellingDictionary into the SpellChecker’s Dictionary property. The majority of DI containers support the notion of specifying a default concrete implementation type to use when a base- or interface-type is required.

In this case, the simple container locates the default implementation of ISpellingDictionary by finding a <type> element whose name attribute matches the required type, which in this example is a FileBasedDictionary. Constructor parameter information is provided for the FileBasedDictionary, which the container uses during its call to Activator.CreateInstance().

Listing 6 shows the edited highlights of the container implementation. As you can see, the container code is remarkably straightforward, relying on .NET’s reflection and configuration APIs; TypeElement (whose code is not shown here), for example, extends ConfigurationElement and holds the cached results of reading the configuration file.

“Do I REALLY have to write my own container?”

You can see that writing a Dependency Injection container is relatively easy, but clearly, this is something that you wouldn’t normally want to be doing. Fortunately, numerous containers already exist that support Dependency Injection and more besides. A non-exhaustive list that offer support for .NET includes: Ultimately, all of these containers support code-based and configuration-driven dependency injection, as well as a host of other features including AOP and attribute-driven Dependency Injection. Ultimately, your choice of framework will depend on how you value these features, and the confidence that you have in the code.

One thing that can be a little confusing is that these containers are often termed Inversion of Control (IoC) containers, so it’s time for a quick interlude on IoC.

A quick aside on IoC

IoC is a general principle that describes, as its name suggests, the notion of shifting control from one type to another, with the aim of making a more extensible framework. Arguably, even .NET’s event architecture is an example of IoC: you can extend the use of a Button by connecting arbitrary code to its Click event.

Another example of IoC is the Template Method pattern, which allows a deriving type to inject functionality into the location specified by the base class; a practical example of which is the way that the ASP.NET Page class’ ProcessRequestMain() method operates, allowing page developers to add functionality to each phase of the processing.

Ultimately, therefore, Dependency Injection is an example of IoC, as it supports the notion of injecting implementation into a type, with control passing to the client code, rather than being locked into the object.

So is Dependency Injection a “good thing?”

Clearly, Dependency Injection when coupled with a DI container massively increases the flexibility of an application. For example, changing the dictionary that the application uses can be as simple as this configuration change:
<type name="Demo.ISpellingDictionary"
	typeName=
	"Demo.GoogleApiDictionary, Demo">
	<constructorParameters>
		<parameter name="apiID"
			typeName="System.String"
			value="xxxxx" />
		<parameter name="url"
			typeName="System.String"
			value="http://api..." />
	</constructorParameters>
</type>
The big wins are therefore:
  • flexible, configuration-driven approach
  • ease of testing
  • loose coupling of types
However, there are numerous things that you should consider when opting to use a DI container. Let’s examine a few of them now.

Consideration #1: Using interfaces
Dependency Injection tends to work best when you use interfaces, and that takes extra effort on your part. To be honest, I should have had SpellChecker implement an ISpellCheck interface, to make it easier to reconfigure it for future implementations. That’s one for the next refactoring!

Heavy use of interfaces also brings along its own design challenges. Where should you define the interfaces? Should it be in one big interfaces.dll assembly, or in separate assemblies? How do you keep track of the interfaces? Clearly, having one big interfaces.dll assembly is going to be a bad choice, and consequently you might choose to follow Martin Fowler’s Separated Interface pattern.

Consideration #2: Instance management
The configuration in Listing 5 ensures that you get a new SpellChecker object each time the container’s GetObject<SpellChecker>() method is called. This is fine, and might be exactly what you need. On the other hand, you might want SpellChecker to be Singleton. On the other hand, how would the container work if the implementation of a dictionary needed a back reference to the SpellChecker that it is currently working with?

These issues are trivial to code, but they can be quite complex to express in configuration, rendering your configuration files hard to maintain. Again, by way of example, I added support for Singleton pattern and named instancing to overcome some of these issues in my simple DI container, as shown in Listing 7.

Now the point of showing you this is not so much how the container works (in fact, I’ve deliberately not shown the implementation code), but in how the client does. Here is the client code to get the Singleton SpellChecker object:

Container c = new Container();
SpellChecker sc =
	c.GetObject<SpellChecker>();
Note that it is no different from the previous code that retrieved a new instance for each call to GetObject().

The point here is that the client has no knowledge of the instancing, which may or not be a good thing. Where this can become a problem is that it is harder to see what is going on, either by eye or in the debugger, without trawling through configuration files or container code.

Consideration #3: Dependence on the container
If you start using a DI container, you find yourself bringing a new dependency into the client: the container itself. The deep pitfall to watch out for is code that looks like this:

public class SpellChecker
{
	Container container = new Container();
// rest of class elided
// but will use the Container to make the
// dictionary!
	...
}
This code is perilously close to being a throwback to the initial SpellChecker from Listing 1, which had a tight coupling to the FileBasedDictionary. Now, the SpellChecker is tightly coupled to the Container. Overall result: no real net gain.

Of course, if you implement Container as a Singleton, or if you use a Service Locator to retrieve the container instance, then it does offer a mechanism to allow the SpellChecker to select a dictionary dynamically. However, you can no longer test the SpellChecker independently of the Container/Service Locator.

Consideration #4: Containers as Singletons
In the previous paragraph, I mentioned that you might use the Singleton pattern for the DI container, as it makes it easy to locate it. There are other obvious advantages, in that you might feel that it is easier to cache the configuration information that the container relies upon.

However, Singletons are the bane of many great OO systems. They limit flexibility; preclude effective testing and are harder to mock; remove the ability to have multiple, independent containers; and are potentially harder to code in the face of multi-threading.

Therefore, whenever possible, avoid using a Singleton-based container. You can always feel free to cache your container inside an application-wide store, such as the ASP.NET Cache or the WPF Application object.

Consideration #5: Overuse of DI containers
Dependency Injection can become addictive, up until you reach the point that you never construct an object unless it’s via a DI container. It’s important to realise that Dependency Injection does not necessarily imply the use of a DI container, and that Dependency Injection is a good thing independently of a DI container.

For example, if you wanted to write a unit test on the SpellChecker, there’s nothing wrong with writing code like this:

AlwaysTrueDictionary atd = new
	AlwaysTrueDictionary();
SpellChecker sc = new SpellChecker(atd);
bool expected = true;
bool actual = sc.CheckStream( ... );
Assert.AreEqual<bool>(expected, actual);
The most important thing to remember when using a DI container is that the additional performance cost and inherent code obscurity has to be worth the advantages in flexibility that it brings to the party. In many cases, such as when working on inter-tier code or composite UI applications, DI and DI containers can in fact reduce overall code complexity.

Consideration #6: Named objects
The simple container that I wrote, along with most containers, supports arbitrarily named objects. Thus the small configuration section shown in Listing 7 highlights the use of named objects, allowing the container to use an overload of its GetObject() method:

Container c = new Container();
ISpellingDictionary dictionary = 
	c.GetObject <ISpellingDictionary>(
	"fileDictionary");
One problem with named objects is the loss of refactoring and compile-time support that can occur. The slightest typo in a configuration or code file can leave you tracing throughout the code to find the one misspelled entry.

Whether you use named objects or simply key items on their type, the use of a DI container will add considerable complexity to the configuration aspects of your code.

Consideration #7: “You’re not in Kansas anymore”
The final consideration that I want to list here is that a DI container is yet another framework to learn. Your developers will all need to learn how to use, and more importantly when and when not to use, a DI container. The upside, of course, is that once you’ve mastered the learning curve, your applications will gain considerably from the many benefits that Dependency Injection brings to the table.

Summary

As you develop complex applications, de-coupling your code becomes ever more important. To achieve this, you will often need to consider Dependency Injection as a means of passing into an object all of its dependencies. This allows you to easily test and re-use those types across components and projects.

Having designed your types to support Dependency Injection, you can then use a DI container to perform the injection of those dependencies on behalf of the client code. This allows the client code to request a fully built, ready to run object in minimal code. It also enables you to compose complex object relationships in configuration.

The major downside is the work involved in getting your design right, and learning your preferred choice of DI container, whether it be any of the excellent free implementations of PicoContainer, Spring or Unity.


Dave Wheeler is a freelance consultant, who specialises in the various UI technologies within Microsoft .NET. He also writes and delivers courses for DevelopMentor, including its new Essential Silverlight 2 course.

Listing 1: A simple spell checker

public class SpellChecker
{
	FileBasedDictionary dictionary = new FileBasedDictionary( @"C:\english.dic");
	public bool CheckStream( StreamReader sr, out long offset,
		out List<String> alternatives)
	{
		string word;
		offset = -1;
		alternatives = null;
		while( GetNextWord(sr, out word, out offset))
		{
			if( !dictionary.DoesWordExist(word, out alternatives) )
				return false;
		}
		return true;
	}
	private bool GetNextWord(StreamReader sr, out string word, out long offset)
	{
		... // implementation elided
	}
}
public class FileBasedDictionary
{
	public bool DoesWordExist(string word, out List<String> alternatives)
	{
		... // implementation elided
	}
	public FileBasedDictionary( string path )
	{
		// Code to load dictionary from file not shown
	}
}

Listing 2: The dictionary should really implement an interface

public interface ISpellingDictionary
{
	bool DoesWordExist(string word, out List<String> alternatives);
}
public class FileBasedDictionary : ISpellingDictionary
{
	// Implementation elided
	...
}
public class GoogleApiDictionary : ISpellingDictionary
{
	// implementation elided
	...
}
public class AlwaysTrueDictionary : ISpellingDictionary
{
	public bool DoesWordExist( string word, out List<String> alternatives )
	{
		alternatives = new List<String>() { word };
		return true;
	}
}

Listing 3: Constructor Injection

public class SpellChecker
{
	ISpellingDictionary dictionary;
	public SpellChecker( ISpellingDictionary dictionary )
	{
		this.dictionary = dictionary;
	}
	public bool CheckStream( StreamReader sr, out long offset, out List<String>
		alternatives )
	{
		offset = -1;
		alternatives = null;
		string word;
		while( GetNextWord(sr, out word, out offset) )
		{
			if(!dictionary.DoesWordExist(word, out alternatives))
				return false;
		}
		return true;
	}
	private bool GetNextWord(StreamReader sr, out string word, out long offset)
	{
		... // implementation elided
	}
}

Listing 4: Supporting Property Injection

public class SpellChecker
{
	ISpellingDictionary dictionary;
	public ISpellingDictionary Dictionary
	{
		get { return dictionary; }
		set { dictionary = value; }
	}
	public SpellChecker()
	{ }
	// rest of class elided
}

Listing 5: Configuration for the simple DI container

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<section name="container" type="DemoContainer.Configuration.ContainerSection,
			DemoContainer"/>
	</configSections>
	<container>
		<types>
			<type typeName="Demo.SpellChecker, Demo">
				<properties>
				<property name="Dictionary" isDependency="true" />
				</properties>
			</type>
			<type name="Demo.ISpellingDictionary, Demo"
					typeName="Demo.FileBasedDictionary, Demo">
				<constructorParameters>
		<parameter name="filePath" typeName="System.String" value="C:\english.dic" />
				</constructorParameters>
			</type>
		</types>
	</container>
</configuration>

Listing 6: Edited highlights of the container

public T GetObject<T>() where T : class
{
	Type t = typeof(T);
	return GetObject(t.AssemblyQualifiedName) as T;
}
public object GetObject(string name)
{
	TypeElement ele = GetTypeElementByName( name );
	object o = null;
	object[] ctorParams = GetConstructorParameters(ele);
	o = Activator.CreateInstance(Type.GetType(ele.TypeName), ctorParams);
	SetProperties(o, ele);
	return o;
}
private void SetProperties(object o, TypeElement ele)
{
	if (ele.PropertySetters == null || ele.PropertySetters.Count == 0) return;
	foreach (SetterElement pce in ele.PropertySetters)
	{
		PropertyInfo pi = o.GetType().GetProperty(pce.Name);
		if (pce.IsDependency)
		{
			object val = GetObject(pi.PropertyType.AssemblyQualifiedName);
			pi.SetValue(o, val, null );
		}
		else
		{
			// other code elided for clarity
		}
	}
}
private object[] GetConstructorParameters(TypeElement ele)
{
	// code elided for clarity
	...
}

Listing 7: Managing instancing via configuration

<type typeName="Demo.SpellChecker, Demo" isSingleton="true">
	<properties>
		<property name="Dictionary" ref="fileDictionary" />
	</properties>
</type>
<type name="fileDictionary" typeName="Demo.FileBasedDictionary, Demo"
	isSingleton="true">
	<constructorParameters>
		<parameter name="filePath" value="C:\english.dic" typeName="System.String" />
	</constructorParameters>
</type>

You might also like...

Comments

About the author

Dave Wheeler United Kingdom

Dave Wheeler is a freelance instructor and consultant who specialises in .NET application development. He’s a moderator on Microsoft’s ASP.NET and Silverlight forums and is a regular speaker at ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“A computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are, in short, a perfect match” - Bill Bryson