Lazy Initialization in C#

C# Jun 11, 2022

What is Lazy Initilization?

Lazy initialization refers to delay for creation of an object until it is used for the first time and it prevents waste processing in CPU and memory until you need this resource.

Lazy is thread safe by default, and it controls for us concurrency in multiple threads. For example, when an object is initialized in one thread, If other threads need this object, they can use this object without initialization.

For example, When the program starts, Several objects may be created at startup.
While we may not need all of them at the start of the program. Here we can use lazy to make these objects and postpone the making of these objects when it is first called.

Let's see some example may useful:

In this example, object (HttpClient) doesn't create until first property or method call the lazy value.

     private readonly Lazy<HttpClient> _httpClient;
    
    _httpClient = new Lazy<HttpClient>(new HttpClient());
    
    // some logic...
    
    await _httpClient.Value.GetAsync("https://example.com", cancellationToken);
    
    // end

Let's see some examples that make it clear for us, how thread safe works in lazy.

In this example we have the same result for all threads, because after initialize value in the first thread, other threads only use that value. If you want different value in other threads, you can use ThreadLocal concept.

Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId);
    
var task1 = Task.Run(() =>
{
    Console.WriteLine("number on task1 = {0} ThreadID = {1}", number.Value, Thread.CurrentThread.ManagedThreadId);
});

var task2 = Task.Run(() =>
{
    Console.WriteLine("number on task2 = {0} ThreadID = {1}", number.Value, Thread.CurrentThread.ManagedThreadId);
});

var task3 = Task.Run(() =>
{
    Console.WriteLine("number on task3 = {0} ThreadID = {1}", number.Value, Thread.CurrentThread.ManagedThreadId);
});

await Task.WhenAll(task1, task2, task3);
    
/*  for example we have some output like this:
    number on task1 = 5 ThreadID = 1
    number on task2 = 5 ThreadID = 2
    number on task3 = 5 ThreadID = 3
    
    we have same value for all threads...
*/    

We can see another lazy example in Singleton pattern with thread safe approach:

public sealed class Singleton
{
    private Singleton()
    {
    }
    private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());
    public static Singleton Instance => lazy.Value;
}

Advantage of this approach compare to classic way is:

  1. Guarantees thread-safe object initialization.
  2. Improves the performance
  3. It will not run until called, and we need it.

References:
https://docs.microsoft.com/en-us/dotnet/framework/performance/lazy-initialization
https://csharpindepth.com/articles/singleton

Hope this helps 😀

Tags

Meysam Hadeli

I’m a software engineer with +7 years of experience in developing and designing distributed applications built on top of cutting-edge technologies with interest in Microservices, DDD.

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.