In .NET 4.0 a new set of classes are introduced to defer the creation of expensive objects when not in use. In this article, I have discussed how you can use Lazy classes to ensure that every object is created only when it is required.
.NET 2010 comes with lots of new features. Some relates to Technology
while other relates to language enhancements. The huge class library
that is there with .NET framework is also enriched with new classes. In
.NET 4.0 there is a new set of classes which introduces a new concept
called
Lazy initializes. In this article I am going to discuss how
simply you can use
Lazy initialize to defer the execution of a method
or property for values to whenever it is required.
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
instead as because it is ThreadSafe. In this article we will see how to implement Microsoft's Lazy initializers.
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<T> : It is just a wrapper class that supports lazy initialization.
- ThreadLocal<T> : 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<T>
Lazy<T> creates a thread safe lazy initialization of objects. In case
of critical scenarios where large number os objects to be created for
large number of objects and each object by itself creates a lots of
objects, for instance say there are large number of Customer and for
each customer there are large number of payments, if Customer is an
entity and Payment is also an entity, Customer will contain an array of
Payment objects. Thus each entity require large number of database
calls to ensure that the data is retrieved. This doesn't makes sense.
Using Lazy class you can eliminate this problem.
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<T>
. This will ensure that the
list will be populated only when the Delegate passed to the constructor
of Lazy object is called, and it will only be called when
this.Payments.Value is called. The property IsValueCreated will
evaluate to true when the List is created.
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<object>.
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<T>
Similar to Lazy
, ThreadLocal<T>
creates object local to one thread.
So each individual thread will have its own Lazy initializer object and
hence will create the object multiple times once for each thread. In
.NET 3.5 or before, you can create objects that are local to one thread
using ThreadStatic attribute. But sometimes ThreadStatic fails to
create a truly ThreadLocal<T>
object. Basic static initializer is
initialized for once, in case of ThreadStatic class.
ThreadLocal<T>
creates a wrapper of Lazy<T> and creates a truly ThreadLocal<T> object. 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
.
LazyInitializer
Finally
coming to LazyInitializer, you can create the same implementation of
the Lazy objects without creating the object of Lazy. The
LazyInitializer handles the Lazy implementation internally giving you
static interfaces from outside which enable you to use it without much
heck.
LazyInitializer.EnsureInitialized
method takes two argument, in general. The first one is ref parameter
where you have to pass the value of the variable where you want the
target to be generated and the delegate that generates the output.
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 should you use Lazy Initialization?
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.