.NET 4.0 includes two handy little classes, Lazy<T> and Lazy<T, TMetadata>.

Lazy<T> represents a value that is initialised the first time it is accessed.

// No counting done here
var lineCount = new Lazy<int>(() => CountLines("bigfile.txt"));

// Count happens when value is accessed
Console.Write(lineCount.Value);

// No counting here either - once the value is initialised it is stored
Console.Write(lineCount.Value);

Lazy<T, TMetadata> works exactly the same way as Lazy<T>, but adds a Metadata property that can be used to get information about the value before it is instantiated.

var filename = "bigfile.txt";

// The filename passed in the constructor is stored in the Metadata property
// of type string
var lineCount = new Lazy<int, string>(() => CountLines(filename), filename);

// Metadata (i.e. the filename) can be accessed without causing the value to be initialised
Console.Write(lineCount.Metadata);

Metadata becomes very useful when you have more than one lazy item, and need to choose between them before accessing and initialising the value.

Lazy Dependencies

Components in an IoC container can use the lazy types to express dependencies, and thus delay the construction of part of the object graph either for functional or performance reasons.

One of the very nice features of the Managed Extensibility Framework (MEF) in .NET 4.0 is the way lazy dependencies are handled. An ‘import’ (MEF terminology) of type Lazy<T> will be injected automatically so long as T is registered with the CompositionContainer.

In Autofac’s latest 2.1 beta,  an extension called LazyDependencyModule gives a similar result.

**Autofac 2 still supports .NET 3.5. **The only Autofac assembly that requires .NET 4.0 is Autofac.Integration.Mef.dll, while all others target .NET 3.5.

Simple Lazy Example

Let’s imagine that in our particular ASP.NET application, creating repositories is fairly expensive. In some of the code paths through ContactsController we don’t use the injected contacts repository, and would like to avoid the cost of instantiating it.

Yes dear reader, you need to use your imagination here rather than a profiler… :)

To communicate this requirement to Autofac, you use Lazy<IContactRepository> as the type of the controller constructor parameter:

public class ContactsController : Controller
{
    Lazy<IContactRepository> _contacts;

    public ContactsController(Lazy<IContactRepository> contacts)
    {
        _contacts = contacts;
    }

    public ActionResult Show(int contactId)
    {
        ViewData.Model = _contacts.Value.Load(contactId);
        return View();
    }
}

When configuring your Autofac ContainerBuilder, add the LazyDependencyModule from Autofac.Integration.Mef.dll.


var builder = new ContainerBuilder();

builder.RegisterModule(new LazyDependencyModule());

// No special configuration for the controller...
builder.RegisterType<ContactsController>().Named<IController>("controller.contacts");

// ...or the repository.
builder.RegisterType<ContactRepository>().As<IContactRepository>();

And that’s it! Wherever Lazy<T> is resolved, Autofac will do the right thing.

Using Metadata

I’ve included downloadable code for a more complete example Lazy in Autofac 2 demonstrating metadata use.

The Log component accepts a list of appenders, each with metadata. Based on the logging request, the logger selects an appender (instantiating if necessary) and writes a message to it.

public class Log
{
    readonly IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> _appenders;

    public Log(IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> appenders)
    {
        _appenders = appenders;
    }

    public void Write(string destination, string message)
    {
        var appender = _appenders.First(a => a.Metadata.AppenderName == destination);
        appender.Value.Write(message);
    }
}

You can see in this example how Autofac 2’s automatic support for IEnumerable dependencies works just as well combined with laziness.

The metadata view ILogAppenderMetadata has a single property AppenderName. The value of this property will be retrieved from the implementing component’s extended properties.

builder.Register(c => new ScreenAppender())
    .As<ILogAppender>()
    .WithMetadata("AppenderName", "screen");

Binding of ILogAppenderMetadata to the underlying dictionary of extended properties is done using the same mechanism as MEF uses, and you can find more information on that via the MEF site.

Under the Hood

If you’re interested to see how easy Autofac 2 makes supporting these ‘context adapters’, check out the implementation handling Lazy<T, TMetadata>, weighing in at 52 lines including braces, using statements and whitespace :)

Downloads