Lazy loading is a process of deferring initialization of object to the point till which it is really needed. It is mostly used in web design and can improve page loading time if correctly used.

Basic Lazy Inialization

//Widget Class
public class Widget
{
private int _widgetId;
public Widget()
{

}
public Widget(int id)
{
_widgetId = id;
}
public void SetWidgetId(int widgetId)
{
_widgetId = widgetId;
}
public int GetWidgetId() => _widgetId;
}

A Class MyPreferences which contains property for getting Widget object.


public class MyPreferences
{
private Widget myWidget = null;

public Widget GetMyWidgetObject(int widgetId)
{
myWidget = new Widget(widgetId);
return myWidget;
}

public Widget MyWidget
{
get { return myWidget; }
}
}

This can be said as the simplest way to understand lazy initialization or loading .
Here, it can be seen that myWidget object is getting initialzed “on the fly” only when MyWdiget object is null.

Lazy Loading using .NET defined class.

The .NET Framework defines a class named as Lazy which itself incorporates lazy loading concept , thus making the code more succinct.


public class MyPreferencesLazyLoad
{
private readonly Lazy myLazyWidgetObj;

//default constructor
public MyPreferencesLazyLoad()
{
myLazyWidgetObj = new Lazy();
}
//parameterized constructor.
public MyPreferencesLazyLoad(int widgetId)
{

myLazyWidgetObj = new Lazy(() => new Widget(widgetId));
}
public bool IsWidgetObjectCreated
{
get
{
if (myLazyWidgetObj != null)
{
return myLazyWidgetObj.IsValueCreated;
}
else
{
return false;
}
}
}
public Widget MyWidget
{
get
{

return (myLazyWidgetObj?.Value);
}
}
}

Lazy Loading Techniques:

Lazy class has a property IsValueCreated which can be used to know if the instance of the class has been created.


var lazyLoadMyPreferences = new MyPreferencesLazyLoad(1);
Console.WriteLine();
Console.WriteLine("Lazy object benefit");
Console.WriteLine("Lazy Widget Object created : {0}", lazyLoadMyPreferences.IsWidgetObjectCreated);
Console.WriteLine("WidgetId to be created: {0}",lazyLoadMyPreferences.MyWidget.GetWidgetId());
Console.WriteLine("Lazy Widget Object created : {0}", lazyLoadMyPreferences.IsWidgetObjectCreated);
Console.WriteLine();

We can use Lazy by creating Lazy object either every time when in loop or by creating the instance once and using it in every iteration in the loop. However, due to substantial complexity of Lazy class , it has overhead and performance penalty too. So, it is mostly recommended to use Lazy on slower, simpler but hefty objects like model classes.

Code in which object of Lazy instance is created everytime in loop. This mostly has a performance overhead.


// Version 2: create Lazy every time in loop, and access Value each time.
var s2 = Stopwatch.StartNew();
Console.WriteLine("-------Start 2nd Loop Type- Creating Lazy Loading object fresh in each iteration------");
Console.WriteLine();
for (int i = 0; i < _maxLoppingNumber; i++) { var objMyPreferences = new MyPreferencesLazyLoad(i); //print on every ten thousand loop if ((i / 10000) >= 1 && (i % 10000) == 0)
{
Console.WriteLine("Instance Count :- {0}", objMyPreferences.MyWidget.GetWidgetId());
}
}
s2.Stop();
Console.WriteLine();

Example in which Lazy object is created once and then its reused to access the value of the underlying class. Here is overhead is mostly reduced and performance is greatest.


// Version 3 : create lazy object once , and access Value each time in loop.
var s3 = Stopwatch.StartNew();
Console.WriteLine("------Start 3rd Loop Type- Creating Lazy Loading object once, access Value in each iteration------");
Console.WriteLine();

var objPreferences = new MyPreferencesLazyLoad();
for (int i = 0; i < _maxLoppingNumber; i++) { objPreferences.MyWidget.SetWidgetId(i); //print on every ten thousand loop if ((i / 10000) >= 1 && (i % 10000) == 0)
{
Console.WriteLine(“Instance Count :- {0}”, objPreferences.MyWidget.GetWidgetId());
}
}
s3.Stop();

Results can be seen supporting above arguments.


Console.WriteLine("=======RESULTS BENCHMARKED");
Console.WriteLine();
Console.WriteLine("Loop1 Performance: {0}", ((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _maxLoppingNumber).ToString("0.00 ns"));
Console.WriteLine("Loop2 Performance: {0}", ((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _maxLoppingNumber).ToString("0.00 ns"));
Console.WriteLine("Loop3 Performance: {0}", ((double)(s3.Elapsed.TotalMilliseconds * 1000000) / _maxLoppingNumber).ToString("0.00 ns"));
Console.ReadLine();

}
}

Complete code for this post can be found at this GitHub link.