Introduction
It is true that we often use Lazy initializer in our code by restricting the load of objects using Properties. Thus unless the property is called from the code, the object will not created. A sample of it is :
private List<string> lazystrings = null; public List<string> LazyStrings { get { if (this.lazystrings == null) this.lazystrings = this.GetLazyStrings(); return this.lazystrings; } } private List<string> GetLazyStrings() { List<string> lazystrings = new List<string>(); for (int i = 0; i < 30; i++) { lazystrings.Add(string.Format("Item {0}", i)); } return lazystrings; }
In this case we have wrapped the loading of a List inside a property and hence the object will be loaded only when the object calls the property. This is very common scenario of our daily programming needs.
Microsoft introduces a new technique called LazyInitializer that enables to do this in the same way as we do with the code above, but Microsoft recommends to use Lazy
Lazy Initializers
Lets look how you can use Lazy intializers in .NET 4.0.
There are 3 types in .NET 4.0 which supports Lazy Initialization.
- Lazy
: It is just a wrapper class that supports lazy initialization. - ThreadLocal
: It is the same as Lazy but the only difference is that it stores data on Thread Local basis. - LazyInitializer : Provides static implementation of Lazy initializer which eliminates the overhead of creation of Lazy objects.
Lets start one by one,
Lazy
Lazy
Let us look how to use it :
public class Customer { public string Name { get; set; } public Lazy<IList<Payment>> Payments { get { return new Lazy<IList<Payment>>(() => this.FetchPayments()); } } private IList<Payment> FetchPayments() { List<Payment> payments = new List<Payment>(); payments.Add(new Payment { BillNumber = 1, BillDate = DateTime.Now, PaymentAmount = 200 }); payments.Add(new Payment { BillNumber = 2, BillDate = DateTime.Now.AddDays(-1), PaymentAmount = 540 }); payments.Add(new Payment { BillNumber = 3, BillDate = DateTime.Now.AddDays(-2), PaymentAmount = 700 }); payments.Add(new Payment { BillNumber = 4, BillDate = DateTime.Now, PaymentAmount = 500 }); //Load all the payments here from database return payments; } public Payment GetPayment(int billno) { if (this.Orders.IsValueCreated) { var payments = this.Payments.Value; Payment p = payments.FirstOrDefault(pay => pay.BillNumber.Equals(billno)); return p; } else throw new NotImplementedException("Object is not initialized"); } } public class Payment { public int BillNumber {get;set;} public DateTime BillDate { get; set; } public double PaymentAmount { get; set; } }
Here I have created a class called Payment which has few properties. Each Customer has a list of Payments.You can see in the Customer class, I have created a Lazy
Similar to list, you can also use Lazy binding for normal objects. Just instead of List, you need to create Lazy of Object like Lazy
Note: System.Lazy creates a ThreadSafe object by default. The Default constructor creates object with LazyThreadSafetyMode.ExecutionAndPublication. Thus once an object is created by one thread, the object will be accessible to all other concurrent threads.
ThreadLocal
Similar to Lazy
ThreadLocal
public void CreateThreadLocal() { ThreadLocal<List<float>> local = new ThreadLocal<List<float>>(() => this.GetNumberList(Thread.CurrentThread.ManagedThreadId)); Thread.Sleep(5000); List<float> numbers = local.Value; foreach (float num in numbers) Console.WriteLine(num); } private List<float> GetNumberList(int p) { Random rand = new Random(p); List<float> items = new List<float>(); for(int i = 0; i<10;i++) items.Add(rand.Next(); return items; }
In the above methods, the CreateThreadLocal creates a local thread and takes the lazy object GetNumberList when the Value is called for (just like normal Lazy implementation).
Now if you call CreateThreadLocal using
Thread newThread = new Thread(new ThreadStart(this.CreateThreadLocal)); newThread.Start(); Thread newThread2 = new Thread(new ThreadStart(this.CreateThreadLocal)); newThread2.Start();
Each thread newThread, and newThread2 will contain its own list of List
public void MyLazyInitializer() { List<Payment> items = new List<Payment>(); for (int i = 0; i < 10; i++) { Payment paymentobj = new Payment(); LazyInitializer.EnsureInitialized<Payment>(ref paymentobj, () => { return this.GetPayment(i); }); items.Add(paymentobj); } }
In the above scenario, you can see I have used a LazyInitializer which fetch each Payment object when it is required. The ref parameter takes a class type object explicitly and returns the object to the variable.
When to use Lazy ?
Lazy initializers was introduced in .NET 4.0. But you should note that, it is not always necessary to use Lazy type of initialization. If you are using an object base which is resource consuming and you are sure that every object will not be required for the application to run, you can go for Lazy initializers. Otherwise, it will put additional load on the system. Also Lazy doesn't work very well with ValueTypes, and it is better to avoid it for ValueTypes. So you should use it very cautiously.
Conclusion
I hope you like this post. Lazy is getting very popular day by day and it is better to understand it properly before you use. I hope this article clears your concept. Thanks for reading. Leave your feedback if you wish.
Thank you.
Nice post man...
ReplyDeleteThanks buddy ...
ReplyDeleteMost welcome.
Hey just becoming a member, glad to be in! I'm Norma and I am inspired by my near death experience, I enjoy working and getting balanced :)
ReplyDeleteSooo anyways, plenty about me, see you all-around and hello yet again haha.
PS, how do I change the little picture thingy like some people have, I like it but can't figure it out haha