LazyInitializer vs Lazy<T> class. When to use each one

I'm not sure if you're still looking into this, but I've had to delve into the details of both Lazy<T> and LazyInitializer.EnsureInitialized<T>() recently, so I thought I should share my findings.

First, some numbers. I ran benchmarks using both methods on batches of ten million values using both approaches, testing for memory use with GC.GetTotalMemory(true) and getting Stopwatch timings for instantiation, first value access, and subsequent value accesses:

Lazy<T> Memory Use:                  320,000,000 bytes (32B/instance)
EnsureInitialized<T>() Memory Use:   N/A

Lazy<T> Instantiation Time:          622.01 ms
EnsureInitialized<T>() Inst. Time:   N/A

Lazy<T> First Access:                1,373.50 ms
EnsureInitialized<T>() First Access: 72.94 ms

Lazy<T> Subsequent Accesses:         18.51 ms
EnsureInitialized<T>() Subsequent:   13.75 ms

(I used LazyThreadSafetyMode.PublicationOnly with the Lazy<T>'s, which looks to be the same thread safety approach taken by LazyInitializer by default.)

As you can see, unless I've screwed up my tests somehow (never out of the question!), under these circumstances LazyInitializer is superior in just about every quantifiable way. It has no memory or instantiation overhead, and it's faster both for creating and retrieving the value.

So, why would you want to use Lazy<T>? Well, first, these were the test results on my x64 system, and it's possible you might get different results under other circumstances.

Lazy<T> can also result in clearer and more concise code. return myLazy.Value; is a lot friendlier than return LazyInitializer.EnsureInitialized(ref myValue, () => GetValue(foo));

Additionally, Lazy<T> makes things a lot simpler if you're dealing with a value type, or with a reference type that could legitimately be null. With LazyInitializer, you have to use a second boolean field to keep track of whether the value has been initialized, compounding the code clarity issue. Lazy<T> is also simpler to use if you want stricter thread safety.

And in the grand scheme of things, most of the overhead is probably negligible for a lot of applications (although not always -- the reason I started looking into this is because I was working on an application involving millions of very small lazily-loaded values, and the 32-byte-per-instance overhead of Lazy<T> was actually starting to become inconvenient).

In the end, unless your application is very memory-intensive, I think it's usually going to be a matter of personal preference. For non-null reference types, I personally think LazyInitializer.EnsureInitialized<T>() is a more elegant approach, but I can dig the code clarity argument too.


Lazy<T> (MSDN) is a generic wrapper which allows creating an instance of T on demand by holding a T factory method (Func<T>) and calling it when Value property getter is accessed.

LazyInitializer - static class with a set of static methods, this is just a helper which uses Activator.CreateInstance() (reflection) able to instantiate a given type instance. It does not keep any local private fields and does not expose any properties, so no memory usage overheads.

Worth noting that both classes uses Func<T> as instance factory.

MSDN says in few words about LazyInitializer class:

These routines avoid needing to allocate a dedicated, lazy-initialization instance, instead using references to ensure targets have been initialized as they are accessed.

PS: I found interesting a way how LazyIntiializer checks whether instance already initialized, it just compare a passed in reference to a default(T), nice:

private static T EnsureInitializedCore<T>(ref T target, Func<T> valueFactory) 
    where T : class
{
    T t = valueFactory();
    if (t == null)
    {
       throw new InvalidOperationException(Environment.GetResourceString("Lazy_StaticInit_InvalidOperation"));
    }

    Interlocked.CompareExchange<T>(ref target, t, default(T));
    return target;
}

What seems strange to me, it creates a new instance each time before an actual check:

T t = valueFactory(); 
// ... and only then does check

As the other answers say,

Lazy<T>

  • Typically gives cleaner code: Just initialize with x = new Lazy<T>(_ => new ...) and use x.Value everywhere you access it.

  • Allows different, predefined options for handling initialization and exceptions if multiple threads access the Value property of an uninitialized Lazy<T> object concurrently.

LazyInitializer

  • Saves space and possibly also time: No need to initialize a new Lazy<T> object for every variable you declare.

  • Allows you to delay providing initialization parameters until use time: LazyInitializer.EnsureInitialized(ref x, () => new X(initParameters))

In conlusion, you only need to use LazyInitializer if space (and possibly time) is limited, or if you cannot specify all initialization parameters at declaration time.

Personally I prefer Lazy<T> whenever possible, because I find it gives cleaner code, and I don't have to handle initialization exceptions explicitly myself.

Tags:

C#