Building an IoC container in 15 lines of code
I am writing this post as a result of a discussion in the ALT.Net mailing list and DI containers in Ruby. Since I promised that I would build such a thing, it made it interesting to see how far I can minimize an IoC container.
The result is, as I said, 15 lines of significant code (ignoring blank lines or line with just curly braces).
You can see the sample model on the right. It is fairly typical model, I believe. I want to get the login controller instance without having to worry about the dependencies, and I want to do it in a non invasive way.
How can we handle that?
Well, it is pretty simple, as a matter of fact, here is the full source code for the container:
public class DemoContainer { public delegate object Creator(DemoContainer container); private readonly Dictionary<string, object> configuration
= new Dictionary<string, object>(); private readonly Dictionary<Type, Creator> typeToCreator
= new Dictionary<Type, Creator>(); public Dictionary<string, object> Configuration { get { return configuration; } } public void Register<T>(Creator creator) { typeToCreator.Add(typeof(T),creator); } public T Create<T>() { return (T) typeToCreator[typeof (T)](this); } public T GetConfiguration<T>(string name) { return (T) configuration[name]; } }
Not really hard to figure out, right? And the client code is as simple:
DemoContainer container = new DemoContainer(); //registering dependecies container.Register<IRepository>(delegate { return new NHibernateRepository(); }); container.Configuration["email.sender.port"] = 1234; container.Register<IEmailSender>(delegate { return new SmtpEmailSender(container.GetConfiguration<int>("email.sender.port")); }); container.Register<LoginController>(delegate { return new LoginController( container.Create<IRepository>(), container.Create<IEmailSender>()); }); //using the container Console.WriteLine( container.Create<LoginController>().EmailSender.Port );
I should probably mention that While this handles dependency injection quite nicely, it is absolutely not what I would consider an appropriate container to use. More on that in the next post.
Comments
Rahien,
container.Configuration["email.sender.port"] = 1234;
should be
container.GetConfiguration["email.sender.port"] = 1234;
mmm I think a basic ioc container must consider 3 things
1) configuration
2) lifecycle
3) registering / istantiating
so this lacks in the 2nd point, but is a clever way to use delegates
Why do you have a configuration part? Why not just register a Config object and use? Would cut your IoC container down even further! :-)
/Mats
Comment preview