Lazy initialization in C#

Constructors are used to construct the member variables of a class. As soon as the instance of the class is created the member variables of the class are initialized. This process seems fine if we have member variables which don't take huge memory. But suppose if we have a memory consuming resource and if we are initializing it as member variable, it can be prove to be memory hungary process.

To prevent from initializing the member variable as soon as the instance of class is constructed we can define member variable as property which can be initialized on demand(Lazy initialization). Let's check it through code snippet.

  1. public class ResourceHungry  
  2. {  
  3.  //Class which takes lots of memory if initilized  
  4. }   
  5.    
  6. public class ResourceConsumer  
  7. {  
  8.     ResourceHungry _hungry;  
  9.    
  10.     //Lazy Initialization   
  11.     public ResourceHungry Hungry  
  12.     {  
  13.             
  14.          if(_hungry == null)  
  15.                hungry = new ResourceHungry();  
  16.          return _hungry;   
  17.     }   
  18. }   
Is the code above is thread safe? Definitely not. What if two threads enter if block at the same time, we will end up getting different instance of Hungry for the ResourceConsumer class which is not a good thing.

To make it thread safe we need to have a lock outside if block as shown in the following code snippet.
  1. public class ResourceConsumer  
  2. {  
  3.       ResourceHungry _hungry;  
  4.       readonly object _resourceHungryLock = new object();   
  5.       //Lazy Initialization  
  6.       public ResourceHungry Hungry  
  7.       {  
  8.          lock(_resourceHungryLock )   
  9.          {   
  10.                if(_hungry == null)  
  11.                   hungry = new ResourceHungry();  
  12.               return _hungry;  
  13.          }   
  14.       }  
  15. }  
Lazy<T>

Starting framework 4.0, Lazy<T> class can be used to help with lazy initialization. If instantiated with an argument of true, it implements a thread-safe initialization pattern just described.

To use the Lazy<T>, we need to instantiate the class with the delegate that tells it how to instantiate a new value, and the argument true. We need to access its value via the Value property:
  1. Lazy<ResourceHungry> _resourceHungry= new Lazy<ResourceHungry>(() => new ResourceHungry(), true);  
  2. public ResourceHungry ResourceHungry
  3. {
  4.     get
  5.     { 
  6.          return _resourceHungry.Value;
  7.     }
  8. }  
If we use false as argument in the Lay<T>'s constructor, it implements the thread unsafe lazy initialization pattern that I described at the start of the topic.

 

Ebook Download
View all
Learn
View all