DCSIMG
Using C# 4 to implement lazy initialization - Pini Dayan

Pini Dayan

The best thing about a boolean is even if you are wrong, you are only off by a bit.

Using C# 4 to implement lazy initialization

Sometimes we wish to improve performance and improve memory usage by making sure the Object we create and initialize is really needed. A couple of scenarios that we might thing of are:

  • We have an object that is expensive to create and there might be situations when we don't really need it. Lets say we have an Employee object in memory and this Employee has a property by the name FormerEmployers that describe all the places he worked at. This information is initialized from a DB. If the consumer of this Employee object never reading this data there is no sense filling the memory and bringing this data.

  • We have an expensive Object to create but we want it’s creation only after other expensive objects have created. An example for this is a creation of some large arrays or lists when the application first loads but the other are not necessary immediately.

Up until now days we had to implement this laziness by ourselves. Now we can use the Lazy<T> within .NET 4.

Her are some samples and expiations from MSDN:

To define a lazy-initialized type, for example, MyType, use Lazy<MyType> (Lazy(Of MyType) in Visual Basic), as shown in the following example. If no delegate is passed in the Lazy<T> constructor, the wrapped type is created by using ActivatorCreateInstance() when the value property is first accessed. If the type does not have a default constructor, a run-time exception is thrown.

// Initialize by invoking a specific constructor on Order when Value

// property is accessed

Lazy<Orders> _orders = new Lazy<Orders>(() => new Orders(100));

You can also pass a delegate in the Lazy<T> constructor that invokes a specific constructor overload on the wrapped type at creation time, and perform any other initialization steps that are required, as shown in the following example.

// Initialize by invoking a specific constructor on Order when Value

// property is accessed

Lazy<Orders> _orders = new Lazy<Orders>(() => new Orders(100));

After the Lazy object is created, no instance of Orders is created until the Value property of the Lazy variable is accessed for the first time. On first access, the wrapped type is created and returned, and stored for any future access.

// We need to create the array only if displayOrders is true

if (displayOrders == true)

{

     DisplayOrders(_orders.Value.OrderData);

}

else

{

    // Don't waste resources getting order data.

}

Thread–safe Initialization

Some Lazy<T> constructor overloads have a Boolean parameter named isThreadSafe that is used to specify whether the Value property will be accessed from multiple threads. If you intend to access the property from just one thread, pass in false to obtain a modest performance benefit. If you intend to access the property from multiple threads, pass in true to instruct the Lazy instance to correctly handle race conditions in which one thread throws an exception at initialization time. If you use a constructor that does not have the isThreadSafe parameter, the value defaults to true.

In multi-threaded scenarios, the first thread to access the Value property initializes it for all subsequent accesses on all threads, and all threads share the same data. Therefore, it does not matter which thread initializes the object, and race conditions are benign. If the first thread to initialize Value causes an exception to be thrown, that same exception will be thrown for all subsequent accesses of Value. It is not possible for one thread to raise an exception and another to initialize the object. The following example shows that the same Lazy<int> instance has the same value for three separate threads.

 

// Initialize the integer to the managed thread id of the

// first thread that accesses the Value property.

Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId);

Thread t1 = new Thread(() => Console.WriteLine("number on t1 = {0} ThreadID = {1}",

                                                number.Value,

                                                Thread.CurrentThread.ManagedThreadId));

t1.Start();

Thread t2 = new Thread(() => Console.WriteLine("number on t2 = {0} ThreadID = {1}",

                                               number.Value,

                                               Thread.CurrentThread.ManagedThreadId));

t2.Start();

Thread t3 = new Thread(() => Console.WriteLine("number on t3 = {0} ThreadID = {1}",

                                               number.Value,

                                               Thread.CurrentThread.ManagedThreadId));

t3.Start();

//Ensure that thread IDs are not recycled if the

//first thread completes before the last one starts.

t1.Join();

t2.Join();

t3.Join();

Enjoy :-)

Posted: Apr 08 2010, 10:02 AM by Pini Dayan | with 2 comment(s) |
תגים:,

Comments

LvL 44 asmo sorcerer. Collectors Edition, Telemachus…for sale. | Aion Summit said:

Pingback from  LvL 44 asmo sorcerer. Collectors Edition, Telemachus&#8230;for sale. | Aion Summit

# April 19, 2010 3:55 PM

cna training said:

Great information! I’ve been looking for something like this for a while now. Thanks!

# June 9, 2010 9:09 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: