Complete Guide to Lazy Loading in C#

In creating performance-centric applications one has to be very cautious about how and when objects are created and destroyed.  An early creation of an object is equally dangerous as is delayed clean-up.  When an object is created before it is actually required, the object finds itself residing in a memory stack at much distant location from the place it is referenced – hence requiring more POP and PUSH statements to retrieve its value each time it is referenced.

To optimize this, C# 4.0 introduced Lazy object loading.  Lazy loading refers to creating and initializing of objects only when it is required for the first time.  That means, you can define the object whenever you wish to, but it actually gets created only when you access its method/property/function. So this essay talks about Lazy loading in C# 4.0

Until C# 3.0, you could implement lazy loading explicitly but with C# 4.0 you can just use Lazy<T> class to implement lazy loading.  It is faster, and standard approach to loading objects and is much recommended for better performance and memory optimization.

Using Lazy<T>

For this essay, we will create a Console application and experiment on a very small & simple class Database (as I don’t like using Foo for examples).  The class just has one property Name.

 

Getting Started
  1. class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             // Defining database
  6.             Lazy<Database> database = new Lazy<Database>();
  7.             Console.WriteLine(“Defined database object. Is database object created?”);
  8.             // Check if database object has been initialized
  9.             if (database.IsValueCreated)
  10.                 Console.WriteLine(“Database is initialized now!”);
  11.             else
  12.                 Console.WriteLine(“Database is not initialized yet!”);
  13.             // Will throw an exception.. as it does not have parameter-less constructor
  14.             Console.WriteLine(“Database: Name =” + database.Value.Name);
  15.             // Check if database object has been initialized
  16.             if (database.IsValueCreated)
  17.                 Console.WriteLine(“Database is initialized now!”);
  18.             Console.ReadKey();
  19.         }
  20.     }
  21.     public class Database
  22.     {
  23.         public string Name { get; set; }
  24.         public Database(string name)
  25.         {
  26.             Console.WriteLine(“Database object constructor called”);
  27.             Name = name;
  28.         }
  29.     }

 

When you execute this program it gives you the result as:

Defined database object. Is database object created?
Database is not initialized yet!

followed by an exception: The lazily-initialized type does not have a public, parameterless constructor.

Okay, let’s add a parameter-less constructor to Database class and re-run it.  The new Database class appears like:

Database class
  1. public class Database
  2.     {
  3.         public string Name { get; set; }
  4.         public Database()
  5.         {
  6.             Console.WriteLine(“Database object constructor called”);
  7.             Name = “MyName”;
  8.         }
  9.     }

 

The new output is:

Defined database object. Is database object created?
Database is not initialized yet!
Database object constructor called
Database: Name =MyName
Database is initialized now!

 

Let’s analyse this. When we defined object database (of Lazy<Database>), CLR created an object of Lazy wrapper but not the object of Database class.  When we accessed the property Name of the database object (database.Value.Name), an object of Database class was created & Database constructor was called.   But does it mean, lazy loading always requires a parameter-less constructor of the class that needs to be loaded lazily?  Well, if that is the case it is not the best fit for Business Applications.  So let’s fix that.

Initializing with delegate
  1. // For parameter-based constructor
  2.             Lazy<Database> database = new Lazy<Database>(() =>
  3.                 {
  4.                     Database internalObject = new Database(“MyNewName”);
  5.                     return internalObject;
  6.                 });

 

The new output is:

Defined database object. Is database object created?
Database is not initialized yet!
Database object constructor called
Database: Name =MyNewName
Database is initialized now!

 

Thread-safety with Lazy<T>

If you are building performance centric applications, you would definitely want to use the power of multiple processors/cores using threads.  So is Lazy<T> class thread-safe? Well yes, it’s thread-safe.  You have got multiple options for thread-safety with lazy loading

Thread safety with Lazy<T>
  1. Lazy<Database> database = new Lazy<Database>(() =>
  2.             {
  3.                 Database internalObject = new Database(“MyNewName”);
  4.                 return internalObject;
  5.             }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);

 

ExecutionAndPublication

Only single thread is responsible for initializing of the object (Lazy<T>) in a thread-safe manner.  When you are using this mode, it is preferable not to use lock in the constructor of the object used with Lazy<T> (here Database class).  This mode can cause a lot of trouble on heavy use because the possibility of deadlocks rises with each dependency between the objects.

ExecutionAndPublication
  1. static void Main(string[] args)
  2.         {
  3.             Lazy<Database> database = new Lazy<Database>(() =>
  4.             {
  5.                 Database internalObject = new Database(“MyNewName”);
  6.                 return internalObject;
  7.             }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
  8.             ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDatabase), database);
  9.             ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDatabase), database);
  10.             Console.ReadKey();
  11.         }
  12.         static void ProcessDatabase(object input)
  13.         {
  14.             Lazy<Database> database = input as Lazy<Database>;
  15.             Thread.Sleep(10);
  16.             database.Value.Counter++;
  17.             Console.WriteLine(“Counter : “ + database.Value.Counter + ” at “ + DateTime.Now.ToString());
  18.         }

The output of following code is:

Database object constructor called
Counter : 1 at 23/10/2011 20:59:33
Counter : 2 at 23/10/2011 20:59:33

 

PublicationOnly

All threads create an instance of the object, but only the first completely initialized one is published to all threads. This reduces the amount of deadlocks that can be caused with ExecutionAndPublication.  However, in case multiple-threads can create an object and persist different values.

 

PublicationOnly
  1. Lazy<Database> database = new Lazy<Database>(() =>
  2.             {
  3.                 Database internalObject = new Database(“MyNewName”);
  4.                 return internalObject;
  5.             }, System.Threading.LazyThreadSafetyMode.PublicationOnly);

 

The output of following code is :

Database object constructor called
Database object constructor called
Counter : 1 at 23/10/2011 20:56:19
Counter : 2 at 23/10/2011 20:56:19

None

This is by-far the most risky mode as it is not thread-safe if the instance is accessed from multiple threads.  The behavior is undefined and should be used only if high-performance is desirable on single-thread applications

 

Exception Handling with Lazy<T>

 

Lazy<T> handles exceptions in two ways

  • For a single-threaded lazy-loading, the exception is thrown directly to the consuming class
  • For multiple-threaded lazy-loading (using ExecutionAndPublication mode), the exception during initializing the object is cached and thrown at the first access of the object.  So when the object is initialized, there won’t be any exception thrown.

For multi-threaded applications, it is preferable to handle exceptions at each thread level rather than aggregating them at the main-thread.

 

Final words

Lazy loading using Lazy<T> can be used in many scenario’s such as:

  • Data layer – with ADO.NET, or Entity Framework
  • Reflection – loading assemblies, types, MEF
  • Caching of objects, domain entities

But one should take care of many design related issues while using lazy loading

  • Inconsistent state of objects
  • Hiding of business requirements due to abstraction

I hope this essay helps you to understand and implement lazy loading with C# 4.0

Download the Source Code from SkyDrive

Related Posts: