Learn to be Lazy<T>

Updated: 3/24/2013

 

It sounds funny but it’s a matter of fact that many people work very hard to be lazy.  There are a number of common patterns to this pursuit of…

A common one looks like:

    public static SchemaProvider Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new SchemaProvider();
            }

            return _instance;
        }
    }

Ok, I admit it. I wrote that one in the .NET 3.5 days. Another one I’ve been seeing a lot of lately looks like:

    private DelegateCommand<EditCommandArgs> _editCommand;
    public DelegateCommand<EditCommandArgs> EditCommand
    {
        get { return _editCommand ?? (_editCommand = new DelegateCommand<EditCommandArgs>(EditCommandExecuted)); }
    }

Both of these have issues. 

One being that they are not thread-safe (although depending on how they are used they may never have a problem). 

I think an even more rudimentary issue is why these particular pieces of code are even using lazy instantiation.  As far as I understand it the main reason for lazy instantiation is that code needs to instantiate an object that is expensive either in the time it takes to construct and return the object or in the amount of memory it takes.  The hope being that maybe the code will never have to actually instantiate the object but it it does you don’t want application startup (for instance) to be delayed while the code attempts to construct these objects.

The code at the top could have just:

    private   static  SchemaProvider _instance =  new  SchemaProvider();

The second code block could have just set the variable _editCommand in the constructor and been done with it.

Just for the sake of argument, however, let’s say that there was a valid need to lazily construct some object, hopefully in a thread-safe way.

Good news!  As of .NET 4 the Lazy<T> class is available for all your lazy resource conservation needs.

An example is:

    private static readonly Lazy<IDataProvider> _dataProvider = new Lazy<IDataProvider>(() => new DataProvider(), LazyThreadSafetyMode.ExecutionAndPublication);
    public IDataProvider DataProvider { get { return _dataProvider.Value; } }

If you need even more control over the object creation just use a Func<TResult> delegate instead of a lambda:

    private static readonly Lazy<ILogger> _logger = new Lazy<ILogger>(GetLogger, LazyThreadSafetyMode.ExecutionAndPublication); 
    private static ILogger GetLogger()
    {
      ...
    }
    public ILogger Logger { get { return _logger.Value; } }

Jeffrey Richter covers this very thoroughly in his book ‘CLR via C#’, Chapter 30, ‘The Famous Double-Check Locking Technique’  http://www.amazon.com/CLR-via-Microsoft-Developer-Reference/dp/0735667454/ref=pd_rhf_gw_s_cp_8 showing that the simple patterns you see most don’t really work well if at all any way.  In addition he gives an excellent explanation of the LazyThreadSafetyMode enumeration values with examples.

Leave a Reply

Your email address will not be published. Required fields are marked *