Lazy Creating Expensive Objects

Lazy Creating Expensive Objects

Some objects in .net are expensive to create (because of time taken or setup they do internally) so that Microsoft recommend creating single instances and using them for the "life" of a program rather than continually creating and destroying them as needed throughout the program as we might with strings or DateTimes or other, what we think of as "disposable", objects.

If the class hosting and using the expensive object needs to hold onto a single instance of the expensive object, often the solution is to create a static constructor for the host class and initialise it there.

This can be a problem for unit testing. Because of the way that static constructors fire for the first piece of code we touch so we don't get a chance to setup proxies or mocks or shims. Anything we do that would allow us to setup a test scenario is ruined by the static constructor barging in to try to create the "real" object in memory and possibly reach out to the filesystem, a database or the network. In a test environment that will usually mean that the constructor will fail.

A better way to approach it is to follow the example of .net source itself and lazy create the object we want using a factory pattern. In Azure, for instance, the CloudBlobClient is one such expensive object that we would like to only create once the first time it's needed.


internal static class CloudBlobClientFactory
{
    public static CloudBlobClient Instance
    {
        get
        {
            return instance.Value;
        }
    }

    private static Lazy<CloudBlobClient> instance = new Lazy<CloudBlobClient>(() =>
    {
        var credentials = new StorageCredentials("MyAccount", "This is not a secret key");

        return new CloudStorageAccount(credentials, false).CreateCloudBlobClient();
    });
}

When we need to use it, we do it like this. Instantiation first time, if it does not already exist, and use together in one line.



// create a cloud blob client if one does not already exist or use the existing one
var container = CloudBlobClientFactory.Instance.GetContainerReference(containerName);

// use the container