Thursday, February 16, 2012

Lazy Loading in C# 4.0


Introduction

The “Lazy Loading” design pattern actually equips the developer with the art of providing data only when a property is called for. In other words, it is a on-demand loading. It is an efficient technique to improve performance.

Using the code

For the explanation, I have taken a simple scenario. Say we have classes PersonalLoan and Loan, as shown below.
public class PersonalLoan 
{ 
    public string AccountNumber { get; set; }
    public string AccounHolderName { get; set; }
    public Loan LoanDetail { get; set; }       
    public PersonalLoan(string accountNumber)
    {
        this.AccountNumber = accountNumber;
        this.AccounHolderName = getAccounHolderName(accountNumber);
    } 
}
public class Loan
{
    public string AccountNumber { get; set; }
    public float LoanAmount { get; set; }
    public bool IsLoanApproved { get; set; }
    public Loan(string accountNumber)
    { 
        Console.WriteLine("loan class constructor called.....");
        this.AccountNumber = accountNumber;
        this.LoanAmount = 1000;
        this.IsLoanApproved = true;
        Console.WriteLine("loan object created.....");
    }
}
For explanation's sake, we will assume that AccountNumber and AccounHolderName are not so costly operations in terms of memory occupation and time consumption. On the other hand, LoanDetail is a costly operation and is not used so often. So while designing a class, we may expect that it is better not to have the detail and to populate it when the object property “LoadDetail” is accessed. Please note that the PersonalLoan constructor does not load the LoanDetail property right this point.
In order to archive LazyLoading, we need to change our code a little and it should look like:
public class PersonalLoan
{ 
    private Loan _loanDetail;
    public string AccountNumber { get; set; }
    public string AccounHolderName { get; set; }
    public Loan LoanDetail 
    { 
        get { return _loanDetail ?? (_loanDetail = new Loan(this.AccounNumber)); }
    }
    public PersonalLoan(string accountNumber)
    {
        this.AccounNumber = accountNumber;
        this.AccounHolderName = getAccounHolderName(accountNumber);
    }
} 
In this way, we make sure that “LoanDetail” will be populate only when the property is called rather than when the object for “PersonalLoan” is instantiated. For details, please check PersonalLoan.cs in the attached project.
Now taking this a step ahead, let's look what .NET 4.0 has in this respect. 4.0 introduces a “Lazy<T>” class to support lazy initialization, where “T” specifies the type of object that is being lazily initialized. This is a new feature of C# 4.0 and it can be used when we are working with large objects. The implementation is quite similar to what we have done in the last example.
public class PersonalLoanLazyClass
{
    private readonly Lazy<Loan> lazyLoan;
    public string AccountNumber { get; set; }
    public string AccounHolderName { get; set; }
    public Loan LoanDetail
    {
        get { return this.lazyLoan.Value; }
    }        
    public PersonalLoanLazyClass(string accountNumber)
    {
        Console.WriteLine("PersonalLoanLazyClass Object Initializ: call to costructor....");
        this.AccountNumber = accountNumber;
        this.AccounHolderName = getAccounHolderName(accountNumber);
        this.lazyLoan = new Lazy<Loan>(() => new Loan(this.AccountNumber));
        Console.WriteLine("Completed initialization.......");
    }
}
For details, please check PersonalLoanLazyClass.cs in the attached project. You can check out lazy loading by adding the following lines of code to the executing program:
static void Main(string[] args)
{
    var personalLoan = new PersonalLoanLazyClass("123456789");
    Console.WriteLine("\n\n.......................Press Enter " + 
            "to continue.......................\n\n");
    Console.Read();
    Console.WriteLine(personalLoan.LoanDetail.LoanAmount.ToString());
    Console.Read();
    Console.Read();
}
Output:
output.png


Another Example:
Lazy loading is a pattern which delay initialization of object. C# 4.0 introduced new class which defers the creation of expensive objects when not in use. In this article I’ll explain the use of Lazy<T> class. Suppose we have Customer class and one customer can have many Accounts, if you want show Accounts for one customer, you need to load accounts associated with customer. Loading of accounts can make performance hit badly if data is huge while initializing Customer object. To avoid this situation Lazy loading comes for rescue. Loading of Accounts will only happen when you will use accounts list. This will make sure fast loading of customer object and give performance boost to application.

Here I am explaining example of Customer and Accounts relationship by Lazy loading:
First we create entity classes of Customer and Account:
01.public class Account
02.{
03.public int Id { get; set; }
04. 
05.}
06.public class Customer
07.{
08.public string Name { get; set; }
09.public int CustomerId { get; set; }
10. 
11.public List GetAccounts()
12.{
13.return lazylist.Value;
14.}
15. 
16.Lazy<List<Account>> lazylist;
17. 
18.public Customer(string name, int id)
19.{
20.Console.WriteLine("Initializing Customer Object");
21.Name = name;
22.CustomerId = id;
23.lazylist = new Lazy<List<Account>>(() => { return GetAccountList(id); });
24.Console.WriteLine("Initialization done");
25.}
26. 
27.private List GetAccountList(int id)
28.{
29.Console.WriteLine("Loading Accounts:");
30.List list = new List();
31.Parallel.For(100, 110, (int i) =>
32.{
33.Account a = new Account();
34.a.Id = i;
35.list.Add(a);
36.});
37.return list;
38.}
39.}
In the constructor of customer class, properties are initializing and declaring lazylist object, which is generic List of account and filled by GetAccountList method. This method will only call when lazylist object will be use. Below is main method which shows behavior of lazy loading:
01.static void Main(string[] args)
02.{
03. 
04.Customer cust = new Customer("Neeraj", 1);//constructor should not load accounts
05. 
06.foreach(Account ac in cust.GetAccounts())// it will actually load accounts, ie. lazy loading
07.Console.WriteLine("Id:{0}",ac.Id);
08. 
09.Console.Read();
10.}
In above code when this statement foreach(Account ac in cust.GetAccounts()) is called then acccount list is filled.
Output
Initializing Customer Object
Initialization done
Loading Accounts:
Id:100
Id:101
Id:102
Id:103
Id:104
Id:105
Id:106
Id:107
Id:108
Id:109
Syntax of Lazy<T> object

1.public Lazy();
2.public Lazy(bool isThreadSafe);
3.public Lazy(Func valueFactory);
4.public Lazy(LazyThreadSafetyMode mode);
5.public Lazy(Func valueFactory, bool isThreadSafe);
6.public Lazy(Func valueFactory, LazyThreadSafetyMode mode);
 
Reference:

No comments:

Post a Comment