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.
- public class ResourceHungry
- {
-
- }
-
- public class ResourceConsumer
- {
- ResourceHungry _hungry;
-
-
- public ResourceHungry Hungry
- {
-
- if(_hungry == null)
- hungry = new ResourceHungry();
- return _hungry;
- }
- }
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.
- public class ResourceConsumer
- {
- ResourceHungry _hungry;
- readonly object _resourceHungryLock = new object();
-
- public ResourceHungry Hungry
- {
- lock(_resourceHungryLock )
- {
- if(_hungry == null)
- hungry = new ResourceHungry();
- return _hungry;
- }
- }
- }
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:
- Lazy<ResourceHungry> _resourceHungry= new Lazy<ResourceHungry>(() => new ResourceHungry(), true);
- public ResourceHungry ResourceHungry
- {
- get
- {
- return _resourceHungry.Value;
- }
- }
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.