IOC Containers

Friday, November 14, 2008

Inversion of control is an interesting pattern, but it has a flaw. When building a system following the IOC pattern, the code bloat seems to bubble up to the top. The higher level objects start creating and managing all the required parts. This starts to fall down when you scale it up beyond a small number of objects. The accepted solution is to move most of the object creation into an IOC container, like Windsor, StructureMap, Autofac, etc.

You register a type, and dependencies, with the IOC container and then just ask for it when you need it. That is great, except I don't know how or why they work the way they do. Most people have responded to my questions with the classic open source creed, “you can look at the source.” Reading the source is like reading a scientific research paper. So, I tried building one myself.

public delegate object FactoryDelegate();
public delegate T FactoryDelegate<T>();

public class Repository
{
private readonly Dictionary<Type, FactoryDelegate> factories =
new Dictionary<Type, FactoryDelegate>();

public void Register<T>(FactoryDelegate<T> factoryMethod) where T : class
{
this.factories.Add(typeof(T), () => factoryMethod());
}

public TService GetInstance<TService>() where TService : class
{
Type t = typeof(TService);
if (!this.factories.ContainsKey(t)) return default(TService);
return this.factories[t]() as TService;
}
}

After a few hours of tinkering, my basic IOC container is 16 lines, including error handling.

Usage:

var r = new Repository();
r.Register<IMyClass>(() => new MyClass("a"));
IMyClass m = r.GetInstance<IMyClass>();

A factory method is registered for each type you want the Repository to handle. Each time the GetInstance method is called, it retrieves the stored factory method, executes it, and returns a strongly typed result. I think I will explore this a little more.