Complete Guide to Lazy Loading – Lazy
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 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.
class Program
{
static void Main(string[] args)
{
// Defining database
Lazy<Database> database = new Lazy<Database>();
Console.WriteLine(“Defined database object. Is database object created?”);
// Check if database object has been initialized
if (database.IsValueCreated)
Console.WriteLine(“Database is initialized now!”);
else
Console.WriteLine(“Database is not initialized yet!”);
// Will throw an exception.. as it does not have parameter-less constructor
Console.WriteLine(“Database: Name =” + database.Value.Name);
// Check if database object has been initialized
if (database.IsValueCreated)
Console.WriteLine(“Database is initialized now!”);
Console.ReadKey();
}
}
public class Database
{
public string Name { get; set; }
public Database(string name)
{
Console.WriteLine(“Database object constructor called”);
Name = name;
}
}
When you execute this program it gives you the result as:
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:
public class Database
{
public string Name { get; set; }
public Database()
{
Console.WriteLine(“Database object constructor called”);
Name = “MyName”;
}
}
The new output is:
Let’s analyse this. When we defined object database (of Lazy), 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.
// For parameter-based constructor
Lazy<Database> database = new Lazy<Database>(() =>
{
Database internalObject = new Database(“MyNewName”);
return internalObject;
});
The new output is:
Defined database object. Is database object created?
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 class thread-safe? Well yes, it’s thread-safe. You have got multiple options for thread-safety with lazy loading
Lazy<Database> database = new Lazy<Database>(() =>
{
Database internalObject = new Database(“MyNewName”);
return internalObject;
}, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication
ExecutionAndPublication
Only single thread is responsible for initializing of the object (Lazy) 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 (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.
static void Main(string[] args)
{
Lazy<database> database = new Lazy<database>(() =>
{
Database internalObject = new Database(“MyNewName”);
return internalObject;
}, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDatabase), database);
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDatabase), database);
Console.ReadKey();
}
static void ProcessDatabase(object input)
{
Lazy<database> database = input as Lazy<database>;
Thread.Sleep(10);
database.Value.Counter++;
Console.WriteLine(“Counter : “ + database.Value.Counter + ” at “ + DateTime.Now.ToString());
}
The output of following code is:
Database object constructor called
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.
Lazy<database> database = new Lazy<database>(() =>
{
Database internalObject = new Database(“MyNewName”);
return internalObject;
}, System.Threading.LazyThreadSafetyMode.PublicationOnly);
The output of the following code is:
Database object constructor called
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 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
Reference: Complete Guide to Lazy Loading – Lazy from our NCG partner Punit Ganshani at the Punit Ganshani’s blog.