While Lazy<T> is the go-to solution for lazy initialization in .NET, there's a lesser-known alternative that can be more efficient in certain scenarios: LazyInitializer.EnsureInitialized.
This static method provides thread-safe initialization with some key characteristics:
- Reference types only: Only works with classes, not value types
- Null-based detection: Uses
null to determine if initialization is needed - Memory efficient compared to
System.Lazy<T>: No additional wrapper object required
The method offers several overloads for different scenarios:
C#
// Default constructor initialization
var instance = LazyInitializer.EnsureInitialized(ref _instance);
// Custom factory method
var instance = LazyInitializer.EnsureInitialized(ref _instance, () => new Sample());
// Value factory is called once even if multiple threads needs to initialize the value
var syncLock = new object();
var instance = LazyInitializer.EnsureInitialized(ref _instance, ref syncLock, () => new Sample());
#Thread Safety Considerations
By default, LazyInitializer.EnsureInitialized behaves like LazyThreadSafetyMode.PublicationOnly:
- Multiple threads may create instances simultaneously
- Only the first successful assignment is kept
- Other instances are discarded
For stricter thread safety, use the overload with a synchronization lock to ensure the factory method runs only once.
The main advantage over Lazy<T> is reduced memory overhead. Instead of storing a Lazy<T> wrapper object, you directly store the target instance, saving one field per lazy-initialized value.
Under the hood, the implementation is similar to:
C#
var instance = Volatile.Read(ref _instance) ??
Interlocked.CompareExchange(ref _instance, new Sample(), null);
Meziantou.Analyzer includes rule MA0173 that suggests replacing manual Interlocked.CompareExchange patterns with LazyInitializer.EnsureInitialized.
Meziantou.Analyzer suggesting to use LazyInitializer.EnsureInitialized
Do you have a question or a suggestion about this post? Contact me!