For this post let’s be Lazy.

What is Lazy<T>?

The Lazy<T> class in C# provides a way to delay the instantiation of an object until it is actually needed. This is particularly useful when the object is resource-intensive to create or may not be needed immediately.

Benefits of Lazy Initialization

  1. Performance Optimization: By delaying object creation, you avoid unnecessary overhead if the object is never used.
  2. Resource Management: Reduces memory usage by only allocating resources when necessary.
  3. Thread-Safety: Lazy<T> can be configured to be thread-safe, ensuring that the object is created only once even in multi-threaded environments.

How to Use Lazy<T>

Using Lazy<T> is straightforward. Here’s a basic example:

public class ExpensiveObject
{
    public ExpensiveObject()
    {
        Console.WriteLine("ExpensiveObject created.");
    }
}

class Program
{
    private static Lazy<ExpensiveObject> lazyExpensiveObject = new Lazy<ExpensiveObject>(() => new ExpensiveObject());

    static void Main(string[] args)
    {
        Console.WriteLine("Program started.");
        var obj = lazyExpensiveObject.Value; // ExpensiveObject is created here
        Console.WriteLine("ExpensiveObject accessed.");
    }
}

In this example, ExpensiveObject is not created until the lazyExpensiveObject.Value is accessed for the first time.

Thread-Safety with Lazy<T>

By default, Lazy<T> is thread-safe and ensures that only one instance of the object is created even if multiple threads try to access it simultaneously. You can configure the thread-safety mode using the LazyThreadSafetyMode enumeration:

private static Lazy<ExpensiveObject> lazyExpensiveObject = new Lazy<ExpensiveObject>(() => new ExpensiveObject(), LazyThreadSafetyMode.ExecutionAndPublication);

This is actually the default behavior when passing justa Func<T> to the constructor of the Lazy<T>class. The LazyThreadSafetyMode has also the None value which can be used when you are certain that one thread will initialize the value because this is not thread safe. Lastly, the PublicationOnly exists, which when multiple threads try to initialize the Lazy<T> instance simultaneously, all threads are allowed to run the initialization method (or the parameterless constructor, if there is no initialization method). The first thread to complete initialization sets the value of the Lazy<T>instance.

What is AsyncLazy<T>?

While Lazy<T> is great for synchronous initialization, in modern applications, asynchronous operations are common. Unfortunately, Lazy<T> does not support asynchronous initialization out of the box. To address this, you can implement an AsyncLazy<T> class, which provides the same benefits as Lazy<T>, but for asynchronous operations.

How to Implement AsyncLazy<T>

Here’s a simple implementation of AsyncLazy<T>:

public class AsyncLazy<T>
{
    private readonly Lazy<Task<T>> instance;

    public AsyncLazy(Func<T> factory)
    {
        instance = new Lazy<Task<T>>(() => Task.Run(factory));
    }

    public AsyncLazy(Func<Task<T>> factory)
    {
        instance = new Lazy<Task<T>>(() => Task.Run(factory));
    }

    public Task<T> Value => instance.Value;
}

In this example, ExpensiveAsyncObject is not created and initialized until the asyncLazyExpensiveObject.Value is awaited for the first time.

Conclusion

Both Lazy<T> and AsyncLazy<T> are powerful tools in C# for optimizing performance and resource management. By deferring object creation until it is needed, you can improve the efficiency of your applications. Use them wisely!


Affiliate promo

If you love learning new stuff and want to support me, consider buying a course from Dometrain using this link: Browse courses – Dometrain. Thank you!

Leave a comment

Trending