Over a million developers have joined DZone.

Lazy initialization in .NET - a short overview

·

Lazy initialization is a process by which the objects that are retrieved via a process or operation are not initialized (or instantiated) before the actual need to use them appears. For example, a collection of objects that is retrieved from a specific source is very large, and the developer is not sure that the user will actually call the entire data set at a point in time. To avoid wasting resources, it is possible to initialize that collection in a “lazy” way so that once put together, the objects are not initialized unless the user explicitly calls them.

Prior to .NET 4.0, the most prominent example of lazy initialization was the use of the singleton pattern. Just like this:

public class DataManager
{
static DataManager dmInstance = null;

DataManager()
{
}

public static DataManager GetInstance()
{
if (dmInstance == null)
{
dmInstance = new DataManager();
}

return dmInstance;
}
}

Here, lazy initialization is used when the DataManger instance is called. If the existing instance is null, then a new instance is created. This example is not thread safe –if the instance is evaluated in two or more threads, none of the other threads knows about the existing instance (initialized in one of the threads), so each one of them will create a separate, new instance.

In .NET 4.0, there is the Lazy<T> class that facilitates lazy initialization. Applied to my previous example, if I would have a DataManager class defined with the same purpose and structure, I could use lazy initialization this way:

public class DataManager
{
static Lazy<DataManager> dmInstance = new Lazy<DataManager>(() => new DataManager());

DataManager()
{
}

public static DataManager GetInstance()
{
return dmInstance.Value;
}
}

Since the constructor for DataManager is private, I am using a lamba expression in the Lazy constructor to access it. Mind that there is no DataManager instance in dmInstance until dmInstance.Value is called – only then an active instance of the class is created.

The main advantage gained by using Lazy<T> instead of the one presented above (checking for a null value) is the fact that it is thread-safe, basically applying the “first come – first serve” principle - when a thread creates the instance, it will lock that specific instance and the same value will be available across all threads– those won’t be able to create an instance of their own.

Speaking of me, I am actively using lazy initialization (with the help of Lazy<T>) when working with MEF (Managed Extensibility Framework). For example, I have an import that requests a collection of IWriter (there are multiple instances spread across multiple assemblies):

[ImportMany(typeof(IWriter))]
internal IEnumerable<IWriter> Writer { get; set; }

Once the needed export points are found, the composition engine instantiates them, so I will have many instances of IWriter ready to go, and this actually is tied to every dependency that IWriter might have, and those can be very demanding, resource-wise.

Instead, I can set the collection as one that contains instances of IWriter declared as Lazy:

[ImportMany(typeof(IWriter))]
internal IEnumerable<Lazy<IWriter>> Writer { get; set; }

In this case, no working instances will be present unless I explicitly call them. When I need a specific instance, I can initialize it by calling the Value() method (since it is Lazy<IWriter> and not simply IWriter) without having other instances hanging on there without any use.

Let’s look at another example, using the same collection of IWriter presented above. For example, I want to iterate through the set and call the DisplayMessage() method. The process seems pretty straightforward, however when it is going a bit different for lazy and regular initializations. Using lazy initialization changes the program flow a bit, and you can compare the iteration process that is done with and without “laziness”:

For lazy initialization, the class is instantiated and used instantly – this allows to instantiate the needed object and work with it. This process can be repeated for each object in the collection. Without that, every single stored object is instantiated first, and then the method will be called – this causes a lot of unneeded instances to be produced (in case not all of them are used).

At this point, you might think that there are not that many situations where you can use lazy initialization. And indeed, you probably were working on a lot of projects without it. However, implementing such an approach in many cases can save a lot of resources and speed-up the application workflow, so you might want to consider some code refactoring for processes that require some heavy data processing, access and manipulation to implement lazy initialization.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}