Thursday, May 13, 2010

Lazy<T> and IEnumerable<Lazy<T>> support comes to Unity

If you are familiar with .NET Framework 4.0 or Managed Extensibility Framework, you probably know that there's a type called Lazy<T> which enables lazy instantiation. This type comes in handy when used with any form of dependency injection. Instead of injecting a concrete instance of a service or whatever you want, you can inject instance which wraps the requested type and instantiates it only when the program really needs to use it. Consider the following code which uses - guess what - MEF =)
[Export]
public class Account
{
[Import]
public Lazy<ILogger> Logger { get; set; }

public void Deposit(decimal amount)
{
if (amount < 0)
{
Logger.Value.Log("Amount is less than 0.");
}
}
}
Here you can see a fragment of an Account class implementation which has an ILogger instance injected in lazy manner. As long as the Deposit method is not invoked with a value less than 0, the logger instance is not used, thus, it is actually not created at all! Lazy instantiation is particularly usefull when you are dealing with objects which are expensive to create.

There are some IoC containers which support Lazy<T> out of the box, namely Autofac 2, or Managed Extensibility Framework to name a few (I don't like calling MEF an IoC container, it's rather a composition engine since it is not constrained to inject types, but methods, fields and properties as well - sorry for that). Unfortunately, Unity IoC (even the latest Unity 2.0) is not on that list. Yes, I know. Unity 2.0 has a support for a concept known as automatic factories (you can read more on that here). Basically speaking, automatic factories allow to pull Func<T> - which is a delegate to a function which returns the concrete instance of the requested component when called. The idea is to fire this delegate when the instance is really needed. So you can say this serves the same purpose as Lazy<T>. Yeah, but it is not Lazy<T> ;) Besides, having the ability to pull Lazy<T> enables even better usage of the Unity+MEF integration layer, which is a part of MEF Contrib initiative. You can always find lates sources hosted on github.

OK. How to leverage the Lazy<T> and IEnumerable<Lazy<T>> ? This is a piece of cake. There are three ways of using the extension. If you want to pull a single component, here's how to do that:
unityContainer.RegisterType<IComponent, Component1>();
var lazyComponent = unityContainer.Resolve<Lazy<IComponent>>();
If you want to pull all components registered under a common type, you can do the following:
unityContainer.RegisterType<IComponent, Component1>("component1");
unityContainer.RegisterType<IComponent, Component2>("component2");
unityContainer.RegisterType<IComponent, Component3>();

// A collection of non-lazy components
var collectionOComponents = unityContainer.Resolve<IEnumerable<IComponent>>();

// Lazy collection of components, once resolved, all the components get resolved
var lazyCollectionOfComponents = unityContainer.Resolve<Lazy<IEnumerable<IComponent>>>();

// Concrete collection of lazy loaded components
var collectionOfLazyComponents = unityContainer.Resolve<IEnumerable<Lazy<IComponent>>>();;
One thing to note. Resolving an IEnumerable is not the same as calling ResolveAll! ResolveAll returns only named types, whereas IEnumerable returns everything!
Either way, before you can use anything presented so far, you have to add the extension the the container. It is as simple as calling:
unityContainer.AddNewExtension<LazySupportExtension>();

An important, and nice thing as well, is that the presented stuff is already the part of MEF Contrib. If you use MEF+Unity integration layer, you automatically get this behavior out of the box!
The code sample can be downloaded, as always, from my code gallery here. Enjoy!


kick it on DotNetKicks.com

2 comments:

JazzyJ said...

Cool, thanks for this!

Lee Campbell said...

Thanks for this. Make Unity somewhat useful! :-)