Why and how to use lazy initialization in C# using Lazy<T> API

First of all, why do we need lazy object initialization? The answer is that when initialization of an object for whatever reason is expensive, we would typically wish to instantiate it once and only when it's required. There is an API introduced in .NET Framework called Lazy<T> for this purpose.

Since Lazy<T> API has been introduced in .NET v 4.0,  I have rarely seen developers use it in their source code. It could be related to the fact that now a days, object initialization responsibility has been delegated to the IoC containers. But anyway, there are still legacy codes and some other situations we need to do lazy object initialization in place.

Let's go on with an example. There is a UserDataService class which we need to initialize it once and used it whenever required. The first idea is to have the initialization in the constructor.

class MyClass
{
    private UserDataService _userDataService;
 
    public MyClass()
    {
        _userDataService = new UserDataService();
    }
 
    // Rest of the code
}

Well, it works but the problem is the object will be initialized always with initialization of MyClass.

A famous traditional workaround is to have a Property instead of a Field and do the initialization there:

class MyClass
{
    private UserDataService _UserDataService;
 
    private UserDataService UserDataService
    {
        get
        {
            if (_UserDataService == null)
            {
                _UserDataService = new UserDataService();
            }

            return _UserDataService;
        }
    }
    // Rest of the code
}

Well, it works for most of the cases but we have sort of mixed up the responsibility of a Field and a Property. 

Let's solve the problem with Lazy<T> API:

class MyClass
{
    private Lazy<UserDataService> _userDataService;
 
    public MyClass()
    {
        _userDataService = new Lazy<UserDataService>(() => new UserDataService());
    }
    // Rest of the code
}

That's it! With using Lazy<T> API, we moved the declaration to the constructor and after the first call to _userDataService.Value, initialization will occur.

One interesting fact about Lazy<T> is that it is Thread-Safe by nature. That means if several threads hit the following line, the first thread does the initialization and the others will use the same instance.

_userDataService = new Lazy<UserDataService>(() => new UserDataService());

Worthwhile to say that there is another class called ThreadLocal<T> which dose the similar job but every thread will have their own initialization and instance. 

More information about Lazy<T> like exception handling and so on, could be found here.

Happy Programming!

No Comments