What is Dependency Injection?

This post will help you understand what DI (Dependency Injection) is, and how easy you can adopt the design patterns to create flexible and testable code. For a definition take a look at this Wikipedia article.

From the three types of Dependency Injection

  • constructor injection
  • setter injection
  • interface injection

this post covers the interface type.

The example will deal with a SharePoint list. This list can either be the posts list of a blog, or the comments list. The distinction is necessary, as both lists have different fields, which might be used for querying data later.

class Program
{
	static void Main(string[] args)
	{
		var list = new SharePointList {SharePointListType = SharePointList.ListType.Posts};
		Console.WriteLine("Posts:\t\t"+list.GetListTitle());

		list = new SharePointList{SharePointListType = SharePointList.ListType.Comments};
		Console.WriteLine("Comments:\t"+list.GetListTitle());
	}
}

class SharePointList
{
	internal enum ListType
	{
		Posts,
		Comments
	}

	private string _listTitle;

	public ListType SharePointListType { get; set; }

	public string GetListTitle()
	{
		switch (SharePointListType)
		{
			case ListType.Posts:
				_listTitle = GetListTitleFromSomewhere("Posts");
				break;
			case ListType.Comments:
				_listTitle = GetListTitleFromSomewhere("Comments");
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}
		return _listTitle;
	}

	private string GetListTitleFromSomewhere(string listName)
	{
		// dummy
		return Guid.NewGuid().ToString();
	}
}

It produces two lines on the console, with different GUIDs as list titles.

What is the problem with this code? Why are we talking about Dependency Injection?

Look at the code above again, and consider this new requirement to your code:

I need the categories list as well..

To fulfill this new requirement, you’ll need to extend the enum and the code within the switch statement. Wouldn’t it be better to just change the Main method instead?

This is an example of the solution with an interface and implementations for each list type:

internal class Program
{
	private static void Main(string[] args)
	{
		var lists = new List<ISharePointList>
		{
			new PostsList(),
			new CommentsList(),
			new CategoriesList()
		};

		foreach (ISharePointList list in lists)
		{
			list.ConsoleWriteLine();
		}
	}
}

internal interface ISharePointList
{
	string GetListTitle { get; }
	void ConsoleWriteLine();
}

internal class PostsList : ISharePointList
{
	public string GetListTitle { get { return "Posts"; } }

	public void ConsoleWriteLine()
	{
		Console.WriteLine("Posts: " + GetListTitle);
	}
}

internal class CommentsList : ISharePointList
{
	public string GetListTitle { get { return "Comments"; } }

	public void ConsoleWriteLine()
	{
		Console.WriteLine("Comments: " + GetListTitle);
	}
}

internal class CategoriesList : ISharePointList
{
	public string GetListTitle { get { return "Categories"; } }

	public void ConsoleWriteLine()
	{
		Console.WriteLine("Categories: " + GetListTitle);
	}
}

As you can see, the main method now uses three lists. You could even use reflection to get all classes, that implement the interface “ISharePointList” to have even more dynamic within your code.

var lists = new List<ISharePointList>();
var currentAssembly = typeof(Program).Assembly;
var types = currentAssembly.DefinedTypes.Where(type => type.ImplementedInterfaces.Any(i => i == typeof (ISharePointList)));
foreach (TypeInfo typeInfo in types)
{
	lists.Add((ISharePointList) Activator.CreateInstance(typeInfo.AsType()));
}

Of course each list needs its own implementation. But you would need to implement different logic anyway.

Dependency Injection is to pass objects, no matter what exactly they are. They are resolved to their actual type later. After they have been injected into something. In this example the “foreach (ISharePointList list in lists){}” will resolve the actual type.

By implementing the interface you can pass completely different objects, if you need them e.g. for testing purpose. Testing SharePoint is not easy, and it might help to pass a dummy which returns something if the basic logic is working.