I’ve been studying dependency injection and inversion of control after seeing them mentioned, referenced and praised in too many places to ignore. From Martin Fowler’s years’ old hand wave of approval, to the more cutting edge of seemingly everyone involved in ASP.NET MVC, this pattern has gotten a lot of good press. Microsoft has even issued its an application block for it called Unity. All of which is not to say that this must be good because x said so, but I was curious to take a deeper look.
I took a look at a simple example provided by Oren Eini aka Ayende Rahien, prolific blogger and Rhino.Mocks driving force, in a post from late 2007, Building an IoC container in 15 lines of code. He notes in later posts that this is definitely a proof of concept, but it was helpful for me to see how simple dependency injection could be. In essence his container is just a wrapper over a dictionary of constructors, keyed by type.
The container knows which concrete implementation goes with which type, but the code that uses the type does not. Therefore, the code that uses the type is not directly dependant on its concrete implementation, instead this dependency is “injected' at run time by the container. So dependency injection helps you nip a large dependency tree in the bud, which is a pretty strong argument in its favor.
I’ll have more to say on this topic later, and while I won’t copy and paste all of Ayende’s code into my post, I did want to use a trimmed down version of his code to point out an interesting bit of C# behavior I didn’t know about before:
//cut down version of IoC container class
public class DemoContainer
{
public delegate object Creator(DemoContainer container);
private readonly Dictionary typeToCreator
= new Dictionary();
public void Register(Creator creator)
{
typeToCreator.Add(typeof(T), creator);
}
public T Create()
{
return (T)typeToCreator[typeof(T)](this);
}
}
//calling code
DemoContainer container = new DemoContainer();
//registering dependencies
container.Register(delegate
{
return new NHibernateRepository();
});
//using the container to get back the NHibernateRepository
IRepository myRepository = container.Create();
The part of this code that I found hardest to grasp at first was that the Creator delegate is declared with a signature that expects one argument of type DemoContainer, but the anonymous delegate used to create the NHibernateRepository is actually a no argument delegate.
The usual behavior is that a delegate has to match the signature to be bound. However, as Ayende’s post demonstrates, and was confirmed by some work in Visual Studio myself, anonymous delegates with no arguments are a special case in C# that can bind to any delegate with the same return type.
This is explained by an MSDN article as follows:
However, if you omit the empty parens after the delegate keyword altogether, you are defining a special kind of anonymous method, which could be assigned to any delegate with any signature
So an interesting feature of C# 2.0 and beyond that I didn’t know about another benefit of reading other people’s code. Even in a 15 line example, you might learn something new.
* Ayende’s code also provides a nice example of the use of closures. So I’ll give him credit for using two lesser known C# features in just 15 lines.