- Download Sample Code
Introduction
The System.Lazy<T>
class is a very nice .NET Framework class that supports any object lazy initialization. In this tip, I explain with an example how we can use System.Lazy<T>
class for lazy object initialization as well as implement singleton design pattern with the help of System.Lazy<T>
class.
Background
I am waiting for lazy loading feature in .NET Framework. I thought a popular framework like .NET Framework should support that type of feature. Fortunately, it comes with .NET Framework version 4 or later. In this post, I explain in detail with an appropriate example.
Using the Code
At first, I create a Product
entity class that has:
- 2 property members
- and 2
static
method members
GetProductListLazy
GetProductList
public class Product
{
public long Id { get; set; }
public string Title { get; set; }
public Product()
{
Thread.Sleep(5000);
}
public static IList<Lazy<Product>> GetProductListLazy()
{
var product1 = new Lazy<Product>(() =>
new Product { Id = 1, Title = "Product 1" });
var product2 = new Lazy<Product>(() =>
new Product { Id = 2, Title = "Product 2" });
var product3 = new Lazy<Product>(() =>
new Product { Id = 3, Title = "Product 3" });
return new List<Lazy<Product>>
{product1, product2, product3};
}
public static IList<Product> GetProductList()
{
var product1 = new Product
{ Id = 1, Title = "Product 1" };
var product2 = new Product
{ Id = 2, Title = "Product 2" };
var product3 = new Product
{ Id = 3, Title = "Product 3" };
return new List<Product>
(new[]{product1, product2, product3 });
}
}
GetProductListLazy
returns a List of Product
object with Lazy Initialization support with the help of System.Lazy<T>
class.
GetProductList
returns a List of Product
object without any lazy initialization support.
In my Product
class default constructor, I hold code execution for 5 seconds using Thread.Sleep
method
public Product()
{
Thread.Sleep(5000);}
Now, I want to print the number of products containing the list in the console. I just call Product.GetProductList static
method.
IList<Product> list = Product.GetProductList();
Console.WriteLine("Total products in my list: " + list.Count);
To print result (number of items in the list), it takes 15 seconds.
Why, because it first creates 3 instances of Product
class, then adds to the list and returns. Per object creation takes 5 seconds. I explain before I use Thread.Sleep
for achieving that.
On the other hand, if I called Product.GetProductListLazy
method...
IList<Lazy<Product>> list = Product.GetLazyProductList();
Console.WriteLine("Total products in my list: " + list.Count);
...then it prints result (number of items in the list) within a millisecond.
Wow! I got my desired result!
If I iterate that list object, then we can understand in run-time when we actually access any of that object's member, that time object is created.
foreach (Lazy<Product> prod in list)
{
Console.WriteLine(prod.Value.Title);
Console.WriteLine("---------------");
}
We can also use System.Lazy<T>
class to implement Singleton design pattern. If you want to know what is Singleton design pattern, then you can visit:
Implementation code using System.Lazy<T>
class is as follows:
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
Real Life Example
In real life, many scenarios may found that costly objects need to store in variable/collection and later need to access those when it is actually needed, or sometimes based on dynamic logic, we may or may not be needed those. In those cases, if we do not initialize those objects lazily, then it will effect performance and may face Timeout
exception, if it is used in other costly operation/components like:
etc. at object creation time.
Now example would be
I have Product, Order, Customer class, Customer object hold its list of order object.
public class Product
{
public string ProductCode{get;set;}
public string ProductTitle{get;set;}
public Product()
{
}
}
public class Order
{
public long OrderId{get;set;}
public DateTime OrderDateTime{get;set;}
public IList<Product> OrderedProductList{get;set;}
public Order()
{
}
}
public class Customer
{
public long CustomerId{get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
public IList<Order> OrderList{get;set;}
public Customer()
{
}
}
public class CustomerRepository
{
public CustomerRepository()
{
}
public Customer FindCustomer(long customerId)
{
}
}
When our CustomerRepository fetch Customer based on customerId it fetches all customer related data incuding its order collection. So Customer object fetch from database is costly operation. Suppose requirement like:
- Need to show customer full name in a web page.
But in code base i need to fetch a complete Customer object including its relational objects like (Order, Order related to Product) etc. But in another scenario we may need to fulfill other requirement
- Need to show Customer Name with his total order quantity.
So repository class should return a complete Customer object so that we need to fulfill our requirements from a single point. But again if carefully read first requirement,
where only need to show customer full name, it actually kills some performance due to population of order collection. If we can avoid that then this operation will be more faster. In that case we can use System.Lazy<T> class. in that case Customer class looks like:
public class Customer
{
public long CustomerId{get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
public IList<Lazy<Order>> OrderList{get;set;}
public Customer()
{
}
}
When we access Order collection of Customer object that time it populate that list otherwise not. If you explore Object Relational Mapper (ORM) component like NHibernet or some others, you will find that those components follow the lazy initialization stratify. Actually they offer 2 process to load associated objects.
- Eager Loading: It loads associate objects at first time.
- Lazy Loading: It loads associate objects on demand basis.
Conclusion
For the performance point of view lazy initialization is a performance optimization where you differ expensive object creation until just before you need it. The key reason for doing this is that you can avoid creating object completely if you never need it. Actually lazy initialization is delaying initialization until a object is used.
I am really a fan of System.Lazy<T>
class and hope everyone loves it and also thank to the .NET team for the nice feature.
I have attached a code sample with this tip. To create that sample, I used Visual Studio 2012 with .NET Framework 4.5 version.
References