I have been learning the Unity IoC container recently as we will be making use of it in a project I am working on. Like all IoC containers, it makes it nice and easy to automatically construct an object, fulfilling all its dependencies.
One issue that comes up frequently when using IoC containers, is how to implement lazy loading. For example, suppose my class has a dependency on IEmailSender, but only uses it in certain circumstances. I might not wish for the concrete implementation to be created until I actually know I need it.
public class MyClass(IEmailSender emailSender)
One quick way round this is to take a dependency on the container instead. With Unity, the container comes already registered, so you can simply change the constructor prototype. Now you can call container.Resolve<IEmailSender> at the point you are ready to use it.
public class MyClass(IUnityContainer container)
The disadvantage of this solution is that we have now obscured the real dependencies of MyClass. It could ask for anything it likes from the container, and we have to examine the code to find out what it actually uses. Fortunately, there is a way we can solve this using Unity’s ability to allow you to register open generic types.
Suppose we create a generic class called Lazy, that implements ILazy as follows:
public interface ILazy<T> { T Resolve(); T Resolve(string namedInstance); } public class Lazy<T> : ILazy<T> { IUnityContainer container; public Lazy(IUnityContainer container) { this.container = container; } public T Resolve() { return container.Resolve<T>(); } public T Resolve(string namedInstance) { return container.Resolve<T>(namedInstance); } }
Now we need to tell our container to use Lazy when someone asks for ILazy:
container.RegisterType(typeof(ILazy<>),typeof(Lazy<>));
And now that allows us to change our original class to have the following prototype:
public class MyClass(ILazy<IEmailService> emailServiceFactory)
Now we have advertised that our class depends on an IEmailService, but have not created it immediately on construction of MyClass, nor have we allowed MyClass to get at the IUnityContainer itself.