How to use Lazy initialization in C#

Reading Time: 3 minutes

Background

Lazy initialization (instantiation) is a technique to delay the creation of an object until the first time the application requires the object. This technique provides a mechanism to control when an object is created. Lazy initialization provides an advantage of improving performance by avoiding unnecessary computation and memory footprint. The most typical implementation of Lazy instantiation is to augment a Get method, to check if an instance of the object already exists. The Get method creates the instance, if it does not already exist, otherwise it returns the existing instance. In this article I cover how to improve performance using lazy initialization in C#.

Typical usage

  • To create large objects, especially the ones the application will not always use.
  • To create objects which are expensive to create.
  • Singleton pattern implementation.
  • In conjunction with the Factory pattern.

Lazy<T> in C#

The Lazy<T> class has six constructor options. I will only cover two of the six. The first constructor is the parameter-less constructor. It calls the matching (parameter-less) constructor of the object T. The second constructor is a constructor that contains a parameter for a delegate. The delegate defines which constructor to call, for the object T. See the following two examples for the different constructors.

    private static void LazyWithDefaultConstructor()
        {
            Console.WriteLine("Lazy<T> example.");
            // Default constructor
            Lazy<Order> order = new Lazy<Order>();

            Console.WriteLine("Order should not yet have been initialize.");

            order.Value.ClientId = 10;
            Console.WriteLine($"Order has been initialized and client Id set to {order.Value.ClientId}");


            Console.WriteLine("Press Enter to close the application.");
            Console.ReadLine();
        }
lazy initialization
        private static void LazyWithDelegateConstructor()
        {
            Console.WriteLine("Lazy<T> example.");
            // Default constructor
            Lazy<Order> order = new Lazy<Order>(() => new Order(55));

            Console.WriteLine("Order should not yet have been initialize.");

            
            Console.WriteLine($"Order has been initialized and client Id value, set by the constructor is {order.Value.ClientId}");


            Console.WriteLine("Press Enter to close the application.");
            Console.ReadLine();
        }
lazy initialization

A Lazy object does not create an instance of T until the Value property is accessed for the first time. Once initially accessed, the Lazy object creates an instance of T and stores it for future use. In other words, the Value property will always return the same object with which it was initialized.

The Value property is read-only. Therefore, if it is a reference type, a new object cannot be assigned to it. However, any of its public, settable properties can be modified. If Value stores a value type, you cannot modify it. You can, however, create a new variable by providing a different set of parameters to its variable constructor.

Thread safety

As a final note, I like to mention that, by default, Lazy<T> is thread safe. This means that the first thread to access the Value property will cause trigger the object initialization. Every subsequent thread will then receive that same instance. The uniqueness of the object is defined by it’s constructor parameters, if any. For example, if two threads access the Value property of a Lazy object, which is instantiated by the same exact constructor. Both threads will receive the same instance. If the constructor takes a parameter and the parameters are different, each access to the Value property will cause the creation of a new object.

Leave a comment

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