5-minute dependency injection container in C#
I found Misko Hevery's talks on the usefulness of Dependency Injection to be quite persuasive, so I have started using constructor DI in my projects. Unfortunately, some of those involve ASP.NET WebForms applications, and even in the one I just started using ASP.NET MVC there are classes I do not create myself (like the controllers). This means that when I write something like
I am hard-coding a dependency on the concrete ProductRepository class inside ProductController.
There are (at least) two solutions to this. One of them would be to create a property in the ProductController class:
and change the constructor to
This is the usual property dependency injection, and it works quite well. However, I find it annoying to do this for every class, not to mention that I don't like the idea of adding a public property just so I can test the class, since this breaks the information hiding tenet.
A variant of this option is to have two constructors:
A second option would be to use a DI container and do this:
and somehow instruct the program, in the initialization part (like Global.asax.cs), to return a new ProductRepository instance every time I ask for an IProductRepository.
This seems to me a bit more fluent, however the association part in (most of) the existing DI containers seem to be overkill.
So... I came up with a home-made DI container by using the pattern in my previous post:
(The Register() method uses a trick here to convert a Func<T> to a Func<object> so that it can be saved in the dictionary - I should be able to get rid of this once we get covariance / contravariance in .NET 4.0 and Visual Studio 2010.)
The usage is quite simple - this call will associate a type with a function returning instances of that type:
and this call will replace the "new ProductRepository()" call:
(Of course, I don't have to use interfaces here; I can use any type.)
Note that the flexibility of the function allows me to also handle the use cases where I want a singleton returned:
During testing I will want to replace the object being returned with a mock object I control:
It's that simple!
As you can see, I'm quite excited about this... it might not have all the bells and whistles of a mainstream DI container, but I find it quite good for what I need.
Edit: Ok, this might be more of a Service Locator pattern instead of Dependency Injection... I am unclear on the terminology. Useful in any case, though :)
Edit 2: It looks like this pattern does have a problem: it hides dependencies. The constructor dependency injection shows clearly that class A depends on classes B, C, and D. Using a service locator hides that. I think the compromise suggested in the article - create two constructors, one exposing the dependencies and one using the service locator - is the best way for now.
- public class ProductController
- {
- private ProductRepository repository;
- public ProductController()
- {
- repository = new ProductRepository();
- }
- }
I am hard-coding a dependency on the concrete ProductRepository class inside ProductController.
There are (at least) two solutions to this. One of them would be to create a property in the ProductController class:
- public IProductRepository Repository { get; set; }
and change the constructor to
- public ProductController()
- {
- Repository = new ProductRepository();
- }
This is the usual property dependency injection, and it works quite well. However, I find it annoying to do this for every class, not to mention that I don't like the idea of adding a public property just so I can test the class, since this breaks the information hiding tenet.
A variant of this option is to have two constructors:
- public ProductController(): this(new ProductRepository())
- {
- }
- public ProductController(IProductRepository repository)
- {
- Repository = repository;
- }
A second option would be to use a DI container and do this:
- public ProductController()
- {
- repository = Container.Get<IProductRepository>();
- }
and somehow instruct the program, in the initialization part (like Global.asax.cs), to return a new ProductRepository instance every time I ask for an IProductRepository.
This seems to me a bit more fluent, however the association part in (most of) the existing DI containers seem to be overkill.
So... I came up with a home-made DI container by using the pattern in my previous post:
- public class GenericContainer
- {
- private static readonly Dictionary<Type, Func<object>> container =
- new Dictionary<Type, Func<object>>();
- public static void Register<T>(Func<T> func) where T : class
- {
- container.Add(typeof (T), () => func());
- }
- public static void Unregister<T>() where T : class
- {
- container.Remove(typeof (T));
- }
- public static T Get<T>() where T : class
- {
- return container[typeof (T)]() as T;
- }
- }
(The Register() method uses a trick here to convert a Func<T> to a Func<object> so that it can be saved in the dictionary - I should be able to get rid of this once we get covariance / contravariance in .NET 4.0 and Visual Studio 2010.)
The usage is quite simple - this call will associate a type with a function returning instances of that type:
- GenericContainer.Register<IProductRepository>(() => new ProductRepository());
and this call will replace the "new ProductRepository()" call:
- GenericContainer.Get<IProductRepository>();
(Of course, I don't have to use interfaces here; I can use any type.)
Note that the flexibility of the function allows me to also handle the use cases where I want a singleton returned:
- var productRepository = new ProductRepository();
- GenericContainer.Register<IProductRepository>(() => productRepository);
During testing I will want to replace the object being returned with a mock object I control:
- GenericContainer.Register<IProductRepository>(() => new MockProductRepository());
It's that simple!
As you can see, I'm quite excited about this... it might not have all the bells and whistles of a mainstream DI container, but I find it quite good for what I need.
Edit: Ok, this might be more of a Service Locator pattern instead of Dependency Injection... I am unclear on the terminology. Useful in any case, though :)
Edit 2: It looks like this pattern does have a problem: it hides dependencies. The constructor dependency injection shows clearly that class A depends on classes B, C, and D. Using a service locator hides that. I think the compromise suggested in the article - create two constructors, one exposing the dependencies and one using the service locator - is the best way for now.
Comments