Edit

Share via


Lazy<T> Constructors

Definition

Initializes a new instance of the Lazy<T> class.

Overloads

Lazy<T>()

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the parameterless constructor of the target type is used.

Lazy<T>(Boolean)

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the parameterless constructor of the target type and the specified initialization mode are used.

Lazy<T>(Func<T>)

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the specified initialization function is used.

Lazy<T>(LazyThreadSafetyMode)

Initializes a new instance of the Lazy<T> class that uses the parameterless constructor of T and the specified thread-safety mode.

Lazy<T>(T)

Initializes a new instance of the Lazy<T> class that uses a preinitialized specified value.

Lazy<T>(Func<T>, Boolean)

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the specified initialization function and initialization mode are used.

Lazy<T>(Func<T>, LazyThreadSafetyMode)

Initializes a new instance of the Lazy<T> class that uses the specified initialization function and thread-safety mode.

Lazy<T>()

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the parameterless constructor of the target type is used.

C#
public Lazy();

Examples

The following example demonstrates the use of this constructor. It also illustrates the use of the Lazy<T>(Boolean) constructor (specifying true for isThreadSafe) and the Lazy<T>(LazyThreadSafetyMode) constructor (specifying LazyThreadSafetyMode.ExecutionAndPublication for mode). To switch to a different constructor, just change which constructors are commented out.

The example defines a LargeObject class that will be initialized lazily by one of several threads. The two key lines of code in this example are the creation of the initializer and the actual initialization. At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:

C#
lazyLargeObject = new Lazy<LargeObject>();

// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(true);
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication);

The example creates and starts three threads that block on a ManualResetEvent object, so that the example can release the threads all at once. The ThreadProc method that's used by all three threads calls the Value property to get the LargeObject instance:

C#
LargeObject large = lazyLargeObject.Value;

The Lazy<T> class provides locking, so that only one thread is allowed to create the LargeObject instance. The example demonstrates that the other threads all get the same instance.

Note

For simplicity, this example uses a global instance of Lazy<T>, and all the methods are static (Shared in Visual Basic). These are not requirements for the use of lazy initialization.

C#
using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>();

        // The following lines show how to use other constructors to achieve exactly the
        // same result as the previous line:
        //lazyLargeObject = new Lazy<LargeObject>(true);
        //lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication);

        Console.WriteLine(
            "\r\nLargeObject is not created until you access the Value property of the lazy" +
            "\r\ninitializer. Press Enter to create LargeObject.");
        Console.ReadLine();

        // Create and start 3 threads, passing the same blocking event to all of them.
        ManualResetEvent startingGate = new ManualResetEvent(false);
        Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
        foreach (Thread t in threads)
        {
            t.Start(startingGate);
        }

        // Give all 3 threads time to start and wait, then release them all at once.
        Thread.Sleep(100);
        startingGate.Set();

        // Wait for all 3 threads to finish. (The order doesn't matter.)
        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine("\r\nPress Enter to end the program");
        Console.ReadLine();
    }

    static void ThreadProc(object state)
    {
        // Wait for the signal.
        ManualResetEvent waitForStart = (ManualResetEvent) state;
        waitForStart.WaitOne();

        LargeObject large = lazyLargeObject.Value;

        // The following line introduces an artificial delay to exaggerate the race condition.
        Thread.Sleep(5);

        // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
        //            object after creation. You must lock the object before accessing it,
        //            unless the type is thread safe. (LargeObject is not thread safe.)
        lock(large)
        {
            large.Data[0] = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
                large.InitializedBy, large.Data[0]);
        }
    }
}

class LargeObject
{
    int initBy = 0;
    public int InitializedBy { get { return initBy; } }

    public LargeObject()
    {
        initBy = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
    }
    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.

LargeObject was created on thread id 4.
Initialized by thread 4; last used by thread 3.
Initialized by thread 4; last used by thread 4.
Initialized by thread 4; last used by thread 5.

Press Enter to end the program
 */

Remarks

An instance that is created with this constructor may be used concurrently from multiple threads.

The thread safety mode of a Lazy<T> instance that is initialized with this constructor is LazyThreadSafetyMode.ExecutionAndPublication. The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance.

A Lazy<T> instance that is created with this constructor does not cache exceptions. For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

See also

Applies to

.NET 10 and other versions
Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

Lazy<T>(Boolean)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the parameterless constructor of the target type and the specified initialization mode are used.

C#
public Lazy(bool isThreadSafe);

Parameters

isThreadSafe
Boolean

true to make this instance usable concurrently by multiple threads; false to make the instance usable by only one thread at a time.

Examples

The following example demonstrates the use of this constructor to create a lazy initializer that is not thread safe, for scenarios where all access to the lazily initialized object occurs on the same thread. It also demonstrates the use of the Lazy<T>(LazyThreadSafetyMode) constructor (specifying LazyThreadSafetyMode.None for mode. To switch to a different constructor, just change which constructor is commented out.

Note

For code that demonstrates how to use this constructor in multithreaded scenarios (specifying true for isThreadSafe), see the example for the Lazy<T>() constructor.

The example defines a LargeObject class that will be initialized lazily. In the Main method, the example creates a Lazy<T> instance and then pauses. When you press the Enter key, the example accesses the Value property of the Lazy<T> instance, which causes initialization to occur. The constructor of the LargeObject class displays a console message.

Note

For simplicity, this example uses a global instance of Lazy<T>, and all the methods are static (Shared in Visual Basic). These are not requirements for the use of lazy initialization.

C#
using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>(false);

        // The following lines show how to use other constructors to achieve exactly the
        // same result as the previous line:
        //lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.None);

        Console.WriteLine(
            "\r\nLargeObject is not created until you access the Value property of the lazy" +
            "\r\ninitializer. Press Enter to create LargeObject.");
        Console.ReadLine();

        LargeObject large = lazyLargeObject.Value;

        large.Data[11] = 89;

        Console.WriteLine("\r\nPress Enter to end the program");
        Console.ReadLine();
    }
}

class LargeObject
{
    public LargeObject()
    {
        Console.WriteLine("LargeObject was created on thread id {0}.",
            Thread.CurrentThread.ManagedThreadId);
    }
    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.

LargeObject was created on thread id 1.

Press Enter to end the program
 */

Remarks

The thread safety mode of a Lazy<T> instance that is initialized with this constructor is LazyThreadSafetyMode.ExecutionAndPublication if isThreadSafe is true; otherwise, the mode is LazyThreadSafetyMode.None. The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance. To specify the LazyThreadSafetyMode.PublicationOnly mode, use the Lazy<T>(Func<T>, LazyThreadSafetyMode) or Lazy<T>(LazyThreadSafetyMode) constructor.

A Lazy<T> instance that is created with this constructor does not cache exceptions. For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

See also

Applies to

.NET 10 and other versions
Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

Lazy<T>(Func<T>)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the specified initialization function is used.

C#
public Lazy(Func<T> valueFactory);

Parameters

valueFactory
Func<T>

The delegate that is invoked to produce the lazily initialized value when it is needed.

Exceptions

valueFactory is null.

Examples

The following example demonstrates the use of this constructor to provide lazy initialization with exception caching. It also demonstrates the use of the Lazy<T>(Func<T>, Boolean) constructor (specifying true for isThreadSafe) and the Lazy<T>(Func<T>, LazyThreadSafetyMode) constructor (specifying LazyThreadSafetyMode.ExecutionAndPublication for mode). To switch to a different constructor, just change which constructors are commented out.

The example defines a LargeObject class that will be initialized lazily by one of several threads. The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor of the LargeObject class, which demonstrates exception caching. At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:

C#
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);

// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication);

The example creates and starts three threads. The ThreadProc method that's used by all three threads calls the Value property to get the LargeObject instance:

C#
try
{
    LargeObject large = lazyLargeObject.Value;

    // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
    //            object after creation. You must lock the object before accessing it,
    //            unless the type is thread safe. (LargeObject is not thread safe.)
    lock(large)
    {
        large.Data[0] = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
            large.InitializedBy, large.Data[0]);
    }
}
catch (ApplicationException aex)
{
    Console.WriteLine("Exception: {0}", aex.Message);
}

In the constructor of the LargeObject class, the third key section of code throws an exception the first time a LargeObject instance is created, but thereafter allows instance creation to occur:

C#
static int instanceCount = 0;
public LargeObject()
{
    if (1 == Interlocked.Increment(ref instanceCount))
    {
        throw new ApplicationException("Throw only ONCE.");
    }

    initBy = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}

When the example is run, the first thread that tries to create an instance of LargeObject fails, and the exception is caught. You might expect that the next thread would successfully create an instance, but the Lazy<T> object has cached the exception. Because of this, all three threads throw the exception.

Note

For simplicity, this example uses a global instance of Lazy<T>, and all the methods are static (Shared in Visual Basic). These are not requirements for the use of lazy initialization.

C#
using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    static LargeObject InitLargeObject()
    {
        return new LargeObject();
    }

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);

        // The following lines show how to use other constructors to achieve exactly the
        // same result as the previous line:
        //lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
        //lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication);

        Console.WriteLine(
            "\r\nLargeObject is not created until you access the Value property of the lazy" +
            "\r\ninitializer. Press Enter to create LargeObject.");
        Console.ReadLine();

        // Create and start 3 threads, each of which tries to use LargeObject.
        Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
        foreach (Thread t in threads)
        {
            t.Start();
        }

        // Wait for all 3 threads to finish. (The order doesn't matter.)
        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine("\r\nPress Enter to end the program");
        Console.ReadLine();
    }

    static void ThreadProc(object state)
    {
        try
        {
            LargeObject large = lazyLargeObject.Value;

            // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
            //            object after creation. You must lock the object before accessing it,
            //            unless the type is thread safe. (LargeObject is not thread safe.)
            lock(large)
            {
                large.Data[0] = Thread.CurrentThread.ManagedThreadId;
                Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
                    large.InitializedBy, large.Data[0]);
            }
        }
        catch (ApplicationException aex)
        {
            Console.WriteLine("Exception: {0}", aex.Message);
        }
    }
}

class LargeObject
{
    int initBy = 0;
    public int InitializedBy { get { return initBy; } }

    static int instanceCount = 0;
    public LargeObject()
    {
        if (1 == Interlocked.Increment(ref instanceCount))
        {
            throw new ApplicationException("Throw only ONCE.");
        }

        initBy = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
    }
    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.

Exception: Throw only ONCE.
Exception: Throw only ONCE.
Exception: Throw only ONCE.

Press Enter to end the program
 */

Remarks

An instance that is created with this constructor may be used concurrently from multiple threads.

The thread safety mode of a Lazy<T> instance that is initialized with this constructor is LazyThreadSafetyMode.ExecutionAndPublication. The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Exceptions that are thrown by valueFactory are cached. For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

See also

Applies to

.NET 10 and other versions
Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

Lazy<T>(LazyThreadSafetyMode)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class that uses the parameterless constructor of T and the specified thread-safety mode.

C#
public Lazy(System.Threading.LazyThreadSafetyMode mode);

Parameters

mode
LazyThreadSafetyMode

One of the enumeration values that specifies the thread safety mode.

Exceptions

mode contains an invalid value.

Examples

The following example demonstrates the use of this constructor to create a lazy initializer that enables multiple threads to race to create an object lazily. Multiple threads might succeed in creating instances, but all threads use the instance that was created first.

Note

For an example that demonstrates how to use this constructor in single-threaded scenarios (specifying LazyThreadSafetyMode.None for mode), see the Lazy<T>(Boolean) constructor. For an example that demonstrates how to use this constructor to provide locking instead of race conditions in multithreaded scenarios (specifying LazyThreadSafetyMode.ExecutionAndPublication for mode), see the Lazy<T>() constructor.

The example defines a LargeObject class that will be initialized lazily by any of several threads. The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor and finalizer of the LargeObject class. At the beginning of the Main method, the example creates the Lazy<T> object that performs lazy initialization of the LargeObject:

C#
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);

The example creates and starts three threads that block on a ManualResetEvent object, so that the example can release the threads all at once. In the ThreadProc method that's used by all three threads, calling the Value property creates the LargeObject instance:

C#
LargeObject large = lazyLargeObject.Value;

Because the constructor for the Lazy<T> instance specified LazyThreadSafetyMode.PublicationOnly, all three threads are allowed to create LargeObject instances. The example demonstrates this by displaying console messages in the constructor and in the finalizer of the LargeObject class:

C#
public LargeObject()
{
    initBy = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}

~LargeObject()
{
    Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}

However, the Lazy<T> object ensures that only one instance is used by all threads. The output from the example shows that all three threads use the same instance, and also shows that the other two instances can be reclaimed by garbage collection.

Note

For simplicity, this example uses a global instance of Lazy<T>, and all the methods are static (Shared in Visual Basic). These are not requirements for the use of lazy initialization.

C#
using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);

        // Create and start 3 threads, passing the same blocking event to all of them.
        ManualResetEvent startingGate = new ManualResetEvent(false);
        Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
        foreach (Thread t in threads)
        {
            t.Start(startingGate);
        }

        // Give all 3 threads time to start and wait, then release them all at once.
        Thread.Sleep(50);
        startingGate.Set();

        // Wait for all 3 threads to finish. (The order doesn't matter.)
        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine(
            "\r\nThreads are complete. Running GC.Collect() to reclaim the extra instances.");

        GC.Collect();

        // Allow time for garbage collection, which happens asynchronously.
        Thread.Sleep(100);

        Console.WriteLine(
            "\r\nNote that all three threads used the instance that was not collected.");
        Console.WriteLine("Press Enter to end the program");
        Console.ReadLine();
    }

    static void ThreadProc(object state)
    {
        // Wait for the signal.
        ManualResetEvent waitForStart = (ManualResetEvent) state;
        waitForStart.WaitOne();

        LargeObject large = lazyLargeObject.Value;

        // The following line introduces an artificial delay, to exaggerate the race
        // condition.
        Thread.Sleep(5);

        // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
        //            object after creation. You must lock the object before accessing it,
        //            unless the type is thread safe. (LargeObject is not thread safe.)
        lock(large)
        {
            large.Data[0] = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
                large.InitializedBy, large.Data[0]);
        }
    }
}

class LargeObject
{
    int initBy = -1;
    public int InitializedBy { get { return initBy; } }

    public LargeObject()
    {
        initBy = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
    }

    ~LargeObject()
    {
        Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
    }

    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

Constructor: Instance initializing on thread 4
Constructor: Instance initializing on thread 3
Constructor: Instance initializing on thread 5
LargeObject was initialized by thread 4; last used by thread 4.
LargeObject was initialized by thread 4; last used by thread 5.
LargeObject was initialized by thread 4; last used by thread 3.

Threads are complete. Running GC.Collect() to reclaim the extra instances.
Finalizer: Instance was initialized on 3
Finalizer: Instance was initialized on 5

Note that all three threads used the instance that was not collected.
Press Enter to end the program

Instance finalizing; initialized on 4
 */

Remarks

The thread safety mode of a Lazy<T> instance describes the behavior when multiple threads try to initialize the Lazy<T> instance.

A Lazy<T> instance that is created with this constructor does not cache exceptions. For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

See also

Applies to

.NET 10 and other versions
Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

Lazy<T>(T)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class that uses a preinitialized specified value.

C#
public Lazy(T value);

Parameters

value
T

The preinitialized value to be used.

Remarks

An instance created with this constructor is usable by multiple threads concurrently.

Applies to

.NET 10 and other versions
Product Versions
.NET Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Standard 2.1

Lazy<T>(Func<T>, Boolean)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class. When lazy initialization occurs, the specified initialization function and initialization mode are used.

C#
public Lazy(Func<T> valueFactory, bool isThreadSafe);

Parameters

valueFactory
Func<T>

The delegate that is invoked to produce the lazily initialized value when it is needed.

isThreadSafe
Boolean

true to make this instance usable concurrently by multiple threads; false to make this instance usable by only one thread at a time.

Exceptions

valueFactory is null.

Examples

The following example demonstrates the use of this constructor to provide lazy initialization with exception caching, in a scenario with a single thread. It also demonstrates the use of the Lazy<T> constructor (specifying LazyThreadSafetyMode.None for mode). To switch to that constructor, just change which constructor is commented out.

Note

For code that demonstrates how to use this constructor in multithreaded scenarios (specifying true for isThreadSafe), see the example for the Lazy<T>(Func<T>) constructor.

The example defines a LargeObject class that will be initialized lazily by one of several threads. The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor of the LargeObject class, which demonstrates exception caching. At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:

C#
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, false);

// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.None);

In the call to the constructor, the isThreadSafe parameter is false, so the Lazy<T> is not thread safe. Because it's not thread safe, the example calls the Value property three times on the same thread:

C#
for (int i = 0; i < 3; i++)
{
    try
    {
        LargeObject large = lazyLargeObject.Value;
        large.Data[11] = 89;
    }
    catch (ApplicationException aex)
    {
        Console.WriteLine("Exception: {0}", aex.Message);
    }
}

In the constructor of the LargeObject class, the third key section of code throws an exception the first time a LargeObject instance is created, but thereafter allows instance creation to occur:

C#
static bool pleaseThrow = true;
public LargeObject()
{
    if (pleaseThrow)
    {
        pleaseThrow = false;
        throw new ApplicationException("Throw only ONCE.");
    }

    Console.WriteLine("LargeObject was created on thread id {0}.",
        Thread.CurrentThread.ManagedThreadId);
}

When the example is run, the first attempt to create an instance of LargeObject fails, and the exception is caught. You might expect that the next attempt would succeed, but the Lazy<T> object has cached the exception. Because of this, all three attempts throw the exception.

Note

For simplicity, this example uses a global instance of Lazy<T>, and all the methods are static (Shared in Visual Basic). These are not requirements for the use of lazy initialization.

C#
using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    static LargeObject InitLargeObject()
    {
        return new LargeObject();
    }

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, false);

        // The following lines show how to use other constructors to achieve exactly the
        // same result as the previous line:
        //lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.None);

        Console.WriteLine(
            "\r\nLargeObject is not created until you access the Value property of the lazy" +
            "\r\ninitializer. Press Enter to create LargeObject (three tries).");
        Console.ReadLine();

        for (int i = 0; i < 3; i++)
        {
            try
            {
                LargeObject large = lazyLargeObject.Value;
                large.Data[11] = 89;
            }
            catch (ApplicationException aex)
            {
                Console.WriteLine("Exception: {0}", aex.Message);
            }
        }

        Console.WriteLine("\r\nPress Enter to end the program");
        Console.ReadLine();
    }
}

class LargeObject
{
    static bool pleaseThrow = true;
    public LargeObject()
    {
        if (pleaseThrow)
        {
            pleaseThrow = false;
            throw new ApplicationException("Throw only ONCE.");
        }

        Console.WriteLine("LargeObject was created on thread id {0}.",
            Thread.CurrentThread.ManagedThreadId);
    }
    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject (three tries).

Exception: Throw only ONCE.
Exception: Throw only ONCE.
Exception: Throw only ONCE.

Press Enter to end the program
 */

Remarks

The thread safety mode of a Lazy<T> instance that is initialized with this constructor is LazyThreadSafetyMode.ExecutionAndPublication if isThreadSafe is true; otherwise, the mode is LazyThreadSafetyMode.None. The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance.

To specify the LazyThreadSafetyMode.PublicationOnly mode, use the Lazy<T>(Func<T>, LazyThreadSafetyMode) or Lazy<T>(LazyThreadSafetyMode) constructor.

Exceptions that are thrown by valueFactory are cached. For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

See also

Applies to

.NET 10 and other versions
Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

Lazy<T>(Func<T>, LazyThreadSafetyMode)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

Initializes a new instance of the Lazy<T> class that uses the specified initialization function and thread-safety mode.

C#
public Lazy(Func<T> valueFactory, System.Threading.LazyThreadSafetyMode mode);

Parameters

valueFactory
Func<T>

The delegate that is invoked to produce the lazily initialized value when it is needed.

mode
LazyThreadSafetyMode

One of the enumeration values that specifies the thread safety mode.

Exceptions

mode contains an invalid value.

valueFactory is null.

Examples

The following example demonstrates the use of this constructor to create a lazy initializer that enables multiple threads to race to create an object lazily. Multiple threads might succeed in creating instances, but all threads use the instance that was created first. In addition, the example demonstrates that exceptions are never cached when you specify LazyThreadSafetyMode.PublicationOnly, even if initialization is performed by a function instead of by the parameterless constructor of the lazily created type.

Note

For an example that demonstrates how to use this constructor in single-threaded scenarios (specifying LazyThreadSafetyMode.None for mode), see the Lazy<T>(Boolean) constructor. For an example that demonstrates how to use this constructor to provide locking instead of race conditions in multithreaded scenarios (specifying LazyThreadSafetyMode.ExecutionAndPublication for mode), see the Lazy<T>() constructor.

The example defines a LargeObject class that will be initialized lazily by any of several threads. The four key sections of code illustrate the creation of the initializer, the actual initialization, the initialization function, and the constructor and finalizer of the LargeObject class. At the beginning of the Main method, the example creates the Lazy<T> object that performs lazy initialization of the LargeObject:

C#
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
                             LazyThreadSafetyMode.PublicationOnly);

The lazy initializer uses a function to perform the initialization. In this case, a function is required because there is no parameterless constructor for the LargeObject class.

The example creates and starts three threads that block on a ManualResetEvent object, so that the example can release the threads all at once. In the ThreadProc method that's used by all three threads, calling the Value property creates the LargeObject instance:

C#
LargeObject large = null;
try
{
    large = lazyLargeObject.Value;

    // The following line introduces an artificial delay to exaggerate the race condition.
    Thread.Sleep(5);

    // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
    //            object after creation. You must lock the object before accessing it,
    //            unless the type is thread safe. (LargeObject is not thread safe.)
    lock(large)
    {
        large.Data[0] = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
            large.InitializedBy, large.Data[0]);
    }
}
catch (ApplicationException ex)
{
    Console.WriteLine("ApplicationException: {0}", ex.Message);
}

In the third key section of code, the lazy initialization function is called to create the LargeObject instance. The function throws an exception the first time it's called:

C#
static int instanceCount = 0;
static LargeObject InitLargeObject()
{
    if (1 == Interlocked.Increment(ref instanceCount))
    {
        throw new ApplicationException(
            String.Format("Lazy initialization function failed on thread {0}.",
            Thread.CurrentThread.ManagedThreadId));
    }
    return new LargeObject(Thread.CurrentThread.ManagedThreadId);
}

With any other LazyThreadSafetyMode setting, an unhandled exception in the initialization function would be cached. However, LazyThreadSafetyMode.PublicationOnly suppresses exception caching. The output from the example demonstrates that a subsequent attempt to initialize the object succeeds.

Note

The exception message usually appears after messages indicating that other threads have successfully initialized the object. This is because of the delay introduced by throwing and catching the exception.

Because the constructor for the Lazy<T> instance specified LazyThreadSafetyMode.PublicationOnly, all three threads are allowed to create LargeObject instances. The example demonstrates this by displaying console messages in the constructor and in the finalizer of the LargeObject class:

C#
public LargeObject(int initializedBy)
{
    initBy = initializedBy;
    Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}

~LargeObject()
{
    Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}

The Lazy<T> object ensures that only one instance is used by all threads (except the thread where the initialization function throws an exception). The output from the example shows this.

Note

For simplicity, this example uses a global instance of Lazy<T>, and all the methods are static (Shared in Visual Basic). These are not requirements for the use of lazy initialization.

C#
using System;
using System.Threading;

class Program
{
    static Lazy<LargeObject> lazyLargeObject = null;

    // Factory function for lazy initialization.
    static int instanceCount = 0;
    static LargeObject InitLargeObject()
    {
        if (1 == Interlocked.Increment(ref instanceCount))
        {
            throw new ApplicationException(
                String.Format("Lazy initialization function failed on thread {0}.",
                Thread.CurrentThread.ManagedThreadId));
        }
        return new LargeObject(Thread.CurrentThread.ManagedThreadId);
    }

    static void Main()
    {
        // The lazy initializer is created here. LargeObject is not created until the
        // ThreadProc method executes.
        lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
                                     LazyThreadSafetyMode.PublicationOnly);

        // Create and start 3 threads, passing the same blocking event to all of them.
        ManualResetEvent startingGate = new ManualResetEvent(false);
        Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
        foreach (Thread t in threads)
        {
            t.Start(startingGate);
        }

        // Give all 3 threads time to start and wait, then release them all at once.
        Thread.Sleep(50);
        startingGate.Set();

        // Wait for all 3 threads to finish. (The order doesn't matter.)
        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine(
            "\r\nThreads are complete. Running GC.Collect() to reclaim extra instances.");

        GC.Collect();

        // Allow time for garbage collection, which happens asynchronously.
        Thread.Sleep(100);

        Console.WriteLine("\r\nNote that only one instance of LargeObject was used.");
        Console.WriteLine("Press Enter to end the program");
        Console.ReadLine();
    }

    static void ThreadProc(object state)
    {
        // Wait for the signal.
        ManualResetEvent waitForStart = (ManualResetEvent) state;
        waitForStart.WaitOne();

        LargeObject large = null;
        try
        {
            large = lazyLargeObject.Value;

            // The following line introduces an artificial delay to exaggerate the race condition.
            Thread.Sleep(5);

            // IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
            //            object after creation. You must lock the object before accessing it,
            //            unless the type is thread safe. (LargeObject is not thread safe.)
            lock(large)
            {
                large.Data[0] = Thread.CurrentThread.ManagedThreadId;
                Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
                    large.InitializedBy, large.Data[0]);
            }
        }
        catch (ApplicationException ex)
        {
            Console.WriteLine("ApplicationException: {0}", ex.Message);
        }
    }
}

class LargeObject
{
    int initBy = -1;
    public int InitializedBy { get { return initBy; } }

    public LargeObject(int initializedBy)
    {
        initBy = initializedBy;
        Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
    }

    ~LargeObject()
    {
        Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
    }

    public long[] Data = new long[100000000];
}

/* This example produces output similar to the following:

Constructor: Instance initializing on thread 5
Constructor: Instance initializing on thread 4
ApplicationException: Lazy initialization function failed on thread 3.
LargeObject was initialized by thread 5; last used by thread 5.
LargeObject was initialized by thread 5; last used by thread 4.

Threads are complete. Running GC.Collect() to reclaim extra instances.
Finalizer: Instance was initialized on 4

Note that only one instance of LargeObject was used.
Press Enter to end the program

Finalizer: Instance was initialized on 5
 */

Remarks

The thread safety mode of a Lazy<T> instance describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Exceptions that are thrown by valueFactory are cached, unless mode is LazyThreadSafetyMode.PublicationOnly. For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

See also

Applies to

.NET 10 and other versions
Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0