Lazy<T> Lazy<T> Lazy<T> Lazy<T> Constructors

Определение

Перегрузки

Lazy<T>() Lazy<T>() Lazy<T>()

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используется конструктор целевого типа по умолчанию.When lazy initialization occurs, the default constructor of the target type is used.

Lazy<T>(Boolean) Lazy<T>(Boolean) Lazy<T>(Boolean) Lazy<T>(Boolean)

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используются конструктор целевого типа по умолчанию и заданный режим инициализации.When lazy initialization occurs, the default constructor of the target type and the specified initialization mode are used.

Lazy<T>(Func<T>) Lazy<T>(Func<T>) Lazy<T>(Func<T>) Lazy<T>(Func<T>)

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используется заданная функция инициализации.When lazy initialization occurs, the specified initialization function is used.

Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode)

Инициализирует новый экземпляр класса Lazy<T>, который использует конструктор T по умолчанию и заданный потокобезопасный режим.Initializes a new instance of the Lazy<T> class that uses the default constructor of T and the specified thread-safety mode.

Lazy<T>(T) Lazy<T>(T) Lazy<T>(T) Lazy<T>(T)

Инициализирует новый экземпляр класса Lazy<T>, использующий предварительно инициализированное заданное значение.Initializes a new instance of the Lazy<T> class that uses a preinitialized specified value.

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

Инициализирует новый экземпляр класса Lazy<T>.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) Lazy<T>(Func<T>, LazyThreadSafetyMode) Lazy<T>(Func<T>, LazyThreadSafetyMode) Lazy<T>(Func<T>, LazyThreadSafetyMode)

Инициализирует новый экземпляр класса Lazy<T>, который использует заданную функцию инициализации и потокобезопасный режим.Initializes a new instance of the Lazy<T> class that uses the specified initialization function and thread-safety mode.

Lazy<T>() Lazy<T>() Lazy<T>()

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используется конструктор целевого типа по умолчанию.When lazy initialization occurs, the default constructor of the target type is used.

public:
 Lazy();
public Lazy ();
Public Sub New ()

Примеры

Ниже приведен пример использования этого конструктора.The following example demonstrates the use of this constructor. Он также демонстрирует использование Lazy<T>(Boolean) конструктор (указание true для isThreadSafe) и Lazy<T>(LazyThreadSafetyMode) конструктор (указание LazyThreadSafetyMode.ExecutionAndPublication для mode).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.

В этом примере определяется класс LargeObject, для которого будет выполняться отложенная инициализация одним из нескольких потоков.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. В начале метода Main в этом примере создается потокобезопасный отложенный инициализатор для класса LargeObject:At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:

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);
lazyLargeObject = New Lazy(Of LargeObject)()

' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line: 
'lazyLargeObject = New Lazy(Of LargeObject)(True)
'lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.ExecutionAndPublication)

В примере создает и запускает три потока, которые блокируют на ManualResetEvent объекта, так что пример может освободить потоков за один раз.The example creates and starts three threads that block on a ManualResetEvent object, so that the example can release the threads all at once. ThreadProc Метод, используемый вызовами все три потока Value свойство для получения LargeObject экземпляр:The ThreadProc method that's used by all three threads calls the Value property to get the LargeObject instance:

LargeObject large = lazyLargeObject.Value;
Dim large As LargeObject = lazyLargeObject.Value

Lazy<T> Класс предоставляет блокировку, чтобы только один поток может создавать LargeObject экземпляра.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.

Примечание

Для простоты в этом примере используется глобальный экземпляр класса Lazy<T>, а все методы объявлены как static (Shared в Visual Basic).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.

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
 */
Imports System
Imports System.Threading

Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of LargeObject)()

        ' The following lines show how to use other constructors to achieve exactly the
        ' same result as the previous line: 
        'lazyLargeObject = New Lazy(Of LargeObject)(True)
        'lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.ExecutionAndPublication)


        Console.WriteLine( _
            vbCrLf & "LargeObject is not created until you access the Value property of the lazy" _
            & vbCrLf & "initializer. Press Enter to create LargeObject.")
        Console.ReadLine()

        ' Create and start 3 threads, passing the same blocking event to all of them.
        Dim startingGate As New ManualResetEvent(False)
        Dim threads() As Thread = { New Thread(AddressOf ThreadProc), 
            New Thread(AddressOf ThreadProc), New Thread(AddressOf ThreadProc) }
        For Each t As Thread In threads
            t.Start(startingGate)
        Next t

        ' 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.)
        For Each t As Thread In threads
            t.Join()
        Next t

        Console.WriteLine(vbCrLf & "Press Enter to end the program")
        Console.ReadLine()
    End Sub


    Private Shared Sub ThreadProc(ByVal state As Object)
        ' Wait for the signal.
        Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
        waitForStart.WaitOne()

        Dim large As LargeObject = 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.)
        SyncLock large
            large.Data(0) = Thread.CurrentThread.ManagedThreadId
            Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
                large.InitializedBy, large.Data(0))
        End SyncLock
    End Sub
End Class

Class LargeObject
    Private initBy As Integer = 0
    Public ReadOnly Property InitializedBy() As Integer
        Get
            Return initBy
        End Get
    End Property

    Public Sub New()
        initBy = Thread.CurrentThread.ManagedThreadId
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
    End Sub
    Public Data(100000000) As Long
End Class

' 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 3.
'Initialized by thread 3; last used by thread 5.
'Initialized by thread 3; last used by thread 4.
'Initialized by thread 3; last used by thread 3.
'
'Press Enter to end the program

Комментарии

Экземпляр, который создается с помощью этого конструктора могут использоваться одновременно из нескольких потоков.An instance that is created with this constructor may be used concurrently from multiple threads.

Потокобезопасный режим из Lazy<T> экземпляр, который инициализируется этим конструктором LazyThreadSafetyMode.ExecutionAndPublication.The thread safety mode of a Lazy<T> instance that is initialized with this constructor is LazyThreadSafetyMode.ExecutionAndPublication. Режим потокобезопасности описывает поведение, когда несколько потоков пытаются инициализировать Lazy<T> экземпляра.The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Объект Lazy<T> , созданного с помощью этого конструктора не кэширует исключения.A Lazy<T> instance that is created with this constructor does not cache exceptions. Дополнительные сведения см. в описании класса Lazy<T> или перечисления System.Threading.LazyThreadSafetyMode.For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

Дополнительно

Lazy<T>(Boolean) Lazy<T>(Boolean) Lazy<T>(Boolean) Lazy<T>(Boolean)

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используются конструктор целевого типа по умолчанию и заданный режим инициализации.When lazy initialization occurs, the default constructor of the target type and the specified initialization mode are used.

public:
 Lazy(bool isThreadSafe);
public Lazy (bool isThreadSafe);
new Lazy<'T> : bool -> Lazy<'T>
Public Sub New (isThreadSafe As Boolean)

Параметры

isThreadSafe
Boolean Boolean Boolean Boolean

Значение true, если необходимо разрешить параллельное использование этого экземпляра несколькими потоками; значение false, если необходимо разрешить одновременное использование этого экземпляра только одним потоком.true to make this instance usable concurrently by multiple threads; false to make the instance usable by only one thread at a time.

Примеры

Ниже приведен пример использования этого конструктора для создания отложенный инициализатор, который не является потокобезопасным, для сценариев, где весь доступ к неактивно инициализированного объекта происходит в том же потоке.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. Он также демонстрирует использование Lazy<T>(LazyThreadSafetyMode) конструктор (указание LazyThreadSafetyMode.None для mode.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.

Примечание

Для кода, который демонстрирует, как использовать этот конструктор в сценариях с несколькими потоками (указание true для isThreadSafe), см. в примере Lazy<T>() конструктор.For code that demonstrates how to use this constructor in multithreaded scenarios (specifying true for isThreadSafe), see the example for the Lazy<T>() constructor.

В примере определяется LargeObject класс, который будет выполняться отложенная инициализация.The example defines a LargeObject class that will be initialized lazily. В Main метод, в примере создается Lazy<T> экземпляр и затем паузы.In the Main method, the example creates a Lazy<T> instance and then pauses. При нажатии клавиши ввод ключа, пример обращается к Value свойство Lazy<T> экземпляр, который приводит к инициализации возникает.When you press the Enter key, the example accesses the Value property of the Lazy<T> instance, which causes initialization to occur. Конструктор LargeObject класс отображает сообщение в консоли.The constructor of the LargeObject class displays a console message.

Примечание

Для простоты в этом примере используется глобальный экземпляр класса Lazy<T>, а все методы объявлены как static (Shared в Visual Basic).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.

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
 */
Imports System
Imports System.Threading

Friend Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of 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( _
            vbCrLf & "LargeObject is not created until you access the Value property of the lazy" _
            & vbCrLf & "initializer. Press Enter to create LargeObject.")
        Console.ReadLine()

        Dim large As LargeObject = lazyLargeObject.Value

        large.Data(11) = 89

        Console.WriteLine(vbCrLf & "Press Enter to end the program")
        Console.ReadLine()
    End Sub
End Class

Friend Class LargeObject
    Public Sub New()
        Console.WriteLine("LargeObject was created on thread id {0}.", _
            Thread.CurrentThread.ManagedThreadId)
    End Sub
    Public Data(100000000) As Long
End Class

' 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

Комментарии

Потокобезопасный режим из Lazy<T> экземпляр, который инициализируется этим конструктором LazyThreadSafetyMode.ExecutionAndPublication Если isThreadSafetrue; в противном случае используется режим LazyThreadSafetyMode.None.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. Режим потокобезопасности описывает поведение, когда несколько потоков пытаются инициализировать Lazy<T> экземпляра.The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance. Чтобы указать LazyThreadSafetyMode.PublicationOnly режиме Lazy<T>(Func<T>, LazyThreadSafetyMode) или Lazy<T>(LazyThreadSafetyMode) конструктор.To specify the LazyThreadSafetyMode.PublicationOnly mode, use the Lazy<T>(Func<T>, LazyThreadSafetyMode) or Lazy<T>(LazyThreadSafetyMode) constructor.

Объект Lazy<T> , созданного с помощью этого конструктора не кэширует исключения.A Lazy<T> instance that is created with this constructor does not cache exceptions. Дополнительные сведения см. в описании класса Lazy<T> или перечисления System.Threading.LazyThreadSafetyMode.For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

Дополнительно

Lazy<T>(Func<T>) Lazy<T>(Func<T>) Lazy<T>(Func<T>) Lazy<T>(Func<T>)

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используется заданная функция инициализации.When lazy initialization occurs, the specified initialization function is used.

public:
 Lazy(Func<T> ^ valueFactory);
public Lazy (Func<T> valueFactory);
new Lazy<'T> : Func<'T> -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T))

Параметры

valueFactory
Func<T>

Делегат, вызываемый для получения неактивно инициализированного значения, когда оно требуется.The delegate that is invoked to produce the lazily initialized value when it is needed.

Исключения

Примеры

Ниже приведен пример использования этого конструктора для предоставления отложенной инициализации с кэширование исключений.The following example demonstrates the use of this constructor to provide lazy initialization with exception caching. Он также демонстрирует использование Lazy<T>(Func<T>, Boolean) конструктор (указание true для isThreadSafe) и Lazy<T>(Func<T>, LazyThreadSafetyMode) конструктор (указание LazyThreadSafetyMode.ExecutionAndPublication для mode).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.

В этом примере определяется класс LargeObject, для которого будет выполняться отложенная инициализация одним из нескольких потоков.The example defines a LargeObject class that will be initialized lazily by one of several threads. Три основные части кода, иллюстрируют Создание инициализатор, фактическую инициализацию и конструктор LargeObject класс, который демонстрирует кэширование исключений.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. В начале метода Main в этом примере создается потокобезопасный отложенный инициализатор для класса LargeObject:At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:

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);
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)

' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line: 
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)

В примере создает и запускает три потока.The example creates and starts three threads. ThreadProc Метод, используемый вызовами все три потока Value свойство для получения LargeObject экземпляр:The ThreadProc method that's used by all three threads calls the Value property to get the LargeObject instance:

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);
}
Try
    Dim large As LargeObject = 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.)
    SyncLock large
        large.Data(0) = Thread.CurrentThread.ManagedThreadId
        Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
            large.InitializedBy, large.Data(0))
    End SyncLock
Catch aex As ApplicationException
    Console.WriteLine("Exception: {0}", aex.Message)
End Try

В конструкторе класса LargeObject , третий ключа раздела кода создает исключение первом LargeObject экземпляр создается, но после этого позволяет создавать экземпляр возникает: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:

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);
}
Private Shared instanceCount As Integer = 0
Public Sub New()
    If 1 = Interlocked.Increment(instanceCount) Then
        Throw New ApplicationException("Throw only ONCE.")
    End If

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

При запуске примере первый поток, который пытается создать экземпляр LargeObject завершается ошибкой и исключение перехватывается.When the example is run, the first thread that tries to create an instance of LargeObject fails, and the exception is caught. Можно предположить, что следующий поток успешно создать экземпляр, но Lazy<T> объект в кэш исключение.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.

Примечание

Для простоты в этом примере используется глобальный экземпляр класса Lazy<T>, а все методы объявлены как static (Shared в Visual Basic).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.

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
 */
Imports System
Imports System.Threading

Friend Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    Private Shared Function InitLargeObject() As LargeObject
        Return New LargeObject()
    End Function


    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)

        ' The following lines show how to use other constructors to achieve exactly the
        ' same result as the previous line: 
        'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
        'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)


        Console.WriteLine(vbCrLf _
            & "LargeObject is not created until you access the Value property of the lazy" _
            & vbCrLf & "initializer. Press Enter to create LargeObject.")
        Console.ReadLine()

        ' Create and start 3 threads, each of which tries to use LargeObject.
        Dim threads() As Thread = { New Thread(AddressOf ThreadProc), _
            New Thread(AddressOf ThreadProc), New Thread(AddressOf ThreadProc) }
        For Each t As Thread In threads
            t.Start()
        Next t

        ' Wait for all 3 threads to finish. (The order doesn't matter.)
        For Each t As Thread In threads
            t.Join()
        Next t

        Console.WriteLine(vbCrLf & "Press Enter to end the program")
        Console.ReadLine()
    End Sub


    Private Shared Sub ThreadProc(ByVal state As Object)
        Try
            Dim large As LargeObject = 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.)
            SyncLock large
                large.Data(0) = Thread.CurrentThread.ManagedThreadId
                Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
                    large.InitializedBy, large.Data(0))
            End SyncLock
        Catch aex As ApplicationException
            Console.WriteLine("Exception: {0}", aex.Message)
        End Try
    End Sub
End Class

Friend Class LargeObject
    Private initBy As Integer = 0
    Public ReadOnly Property InitializedBy() As Integer
        Get
            Return initBy
        End Get
    End Property

    Private Shared instanceCount As Integer = 0
    Public Sub New()
        If 1 = Interlocked.Increment(instanceCount) Then
            Throw New ApplicationException("Throw only ONCE.")
        End If

        initBy = Thread.CurrentThread.ManagedThreadId
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
    End Sub
    Public Data(99999999) As Long
End Class

' 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
' 

Комментарии

Экземпляр, который создается с помощью этого конструктора могут использоваться одновременно из нескольких потоков.An instance that is created with this constructor may be used concurrently from multiple threads.

Потокобезопасный режим из Lazy<T> экземпляр, который инициализируется этим конструктором LazyThreadSafetyMode.ExecutionAndPublication.The thread safety mode of a Lazy<T> instance that is initialized with this constructor is LazyThreadSafetyMode.ExecutionAndPublication. Режим потокобезопасности описывает поведение, когда несколько потоков пытаются инициализировать Lazy<T> экземпляра.The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Исключения, вызываемые по valueFactory кэшируются.Exceptions that are thrown by valueFactory are cached. Дополнительные сведения см. в описании класса Lazy<T> или перечисления System.Threading.LazyThreadSafetyMode.For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

Дополнительно

Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode) Lazy<T>(LazyThreadSafetyMode)

Инициализирует новый экземпляр класса Lazy<T>, который использует конструктор T по умолчанию и заданный потокобезопасный режим.Initializes a new instance of the Lazy<T> class that uses the default constructor of T and the specified thread-safety mode.

public:
 Lazy(System::Threading::LazyThreadSafetyMode mode);
public Lazy (System.Threading.LazyThreadSafetyMode mode);
new Lazy<'T> : System.Threading.LazyThreadSafetyMode -> Lazy<'T>
Public Sub New (mode As LazyThreadSafetyMode)

Параметры

mode
LazyThreadSafetyMode LazyThreadSafetyMode LazyThreadSafetyMode LazyThreadSafetyMode

Одно из значений перечисления, задающее потокобезопасный режим.One of the enumeration values that specifies the thread safety mode.

Исключения

Параметр mode содержит недопустимое значение.mode contains an invalid value.

Примеры

Ниже приведен пример использования этого конструктора для создания отложенный инициализатор, который позволяет нескольким потокам состязаются за право отложенного создания объекта.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.

Примечание

Пример, в котором показано, как использовать этот конструктор в однопоточных сценариях (указание LazyThreadSafetyMode.None для mode), см. в разделе Lazy<T>(Boolean) конструктор.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. Пример, демонстрирующий этот конструктор используется для предоставления блокировки вместо состояния гонки в сценариях с несколькими потоками (указание LazyThreadSafetyMode.ExecutionAndPublication для mode), см. в разделе Lazy<T>() конструктор.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.

В примере определяется LargeObject класс, который будет выполняться отложенная инициализация одним из нескольких потоков.The example defines a LargeObject class that will be initialized lazily by any of several threads. Три основные части кода, иллюстрируют Создание инициализатор, фактическую инициализацию и конструктор и метод завершения из LargeObject класса.The three key sections of code illustrate the creation of the initializer, the actual initialization, and the constructor and finalizer of the LargeObject class. В начале Main метод, в примере создается Lazy<T> объект, который выполняет отложенной инициализации LargeObject:At the beginning of the Main method, the example creates the Lazy<T> object that performs lazy initialization of the LargeObject:

lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)

В примере создает и запускает три потока, которые блокируют на ManualResetEvent объекта, так что пример может освободить потоков за один раз.The example creates and starts three threads that block on a ManualResetEvent object, so that the example can release the threads all at once. В ThreadProc метод, который используется для всех трех потоков, вызвав Value создает свойство LargeObject экземпляр:In the ThreadProc method that's used by all three threads, calling the Value property creates the LargeObject instance:

LargeObject large = lazyLargeObject.Value;
Dim large As LargeObject = lazyLargeObject.Value

Так как конструктор для Lazy<T> указанный экземпляр LazyThreadSafetyMode.PublicationOnly, все три потока разрешено создавать LargeObject экземпляров.Because the constructor for the Lazy<T> instance specified LazyThreadSafetyMode.PublicationOnly, all three threads are allowed to create LargeObject instances. Это продемонстрировано в примере путем отображения сообщения консоли, в конструкторе и в методе завершения LargeObject класса:The example demonstrates this by displaying console messages in the constructor and in the finalizer of the LargeObject class:

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 Sub New()
    initBy = Thread.CurrentThread.ManagedThreadId
    Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub

Protected Overrides Sub Finalize()
    Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub

Тем не менее Lazy<T> объект гарантирует, что только один экземпляр используется всеми потоками.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.

Примечание

Для простоты в этом примере используется глобальный экземпляр класса Lazy<T>, а все методы объявлены как static (Shared в Visual Basic).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.

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
 */
Imports System
Imports System.Threading

Friend Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)


        ' Create and start 3 threads, passing the same blocking event to all of them.
        Dim startingGate As New ManualResetEvent(False)
        Dim threads() As Thread = { _
            New Thread(AddressOf ThreadProc), _
            New Thread(AddressOf ThreadProc), _
            New Thread(AddressOf ThreadProc) _
        }
        For Each t As Thread In threads
            t.Start(startingGate)
        Next t

        ' 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.)
        For Each t As Thread In threads
            t.Join()
        Next t

        Console.WriteLine(vbCrLf & _
            "Threads 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(vbCrLf & _
            "Note that all three threads used the instance that was not collected.")
        Console.WriteLine("Press Enter to end the program")
        Console.ReadLine()

    End Sub


    Private Shared Sub ThreadProc(ByVal state As Object)
        ' Wait for the signal.
        Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
        waitForStart.WaitOne()

        Dim large As LargeObject = 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.)
        SyncLock 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))
        End SyncLock
    End Sub
End Class

Friend Class LargeObject
    Private initBy As Integer = -1
    Public ReadOnly Property InitializedBy() As Integer
        Get
            Return initBy
        End Get
    End Property

    Public Sub New()
        initBy = Thread.CurrentThread.ManagedThreadId
        Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
    End Sub

    Protected Overrides Sub Finalize()
        Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
    End Sub

    Public Data(100000000) As Long
End Class

' This example produces output similar to the following:
'
'Constructor: Instance initializing on thread 3
'Constructor: Instance initializing on thread 5
'Constructor: Instance initializing on thread 4
'LargeObject was initialized by thread 3; last used by thread 4.
'LargeObject was initialized by thread 3; last used by thread 3.
'LargeObject was initialized by thread 3; last used by thread 5.
'
'Threads are complete. Running GC.Collect() to reclaim the extra instances.
'Finalizer: Instance was initialized on 5
'Finalizer: Instance was initialized on 4
'
'Note that all three threads used the instance that was not collected.
'Press Enter to end the program
'
'Finalizer: Instance was initialized on 3
' 

Комментарии

Потокобезопасный режим из Lazy<T> экземпляр описывает поведение, когда несколько потоков пытаются инициализировать Lazy<T> экземпляра.The thread safety mode of a Lazy<T> instance describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Объект Lazy<T> , созданного с помощью этого конструктора не кэширует исключения.A Lazy<T> instance that is created with this constructor does not cache exceptions. Дополнительные сведения см. в описании класса Lazy<T> или перечисления System.Threading.LazyThreadSafetyMode.For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

Дополнительно

Lazy<T>(T) Lazy<T>(T) Lazy<T>(T) Lazy<T>(T)

Инициализирует новый экземпляр класса Lazy<T>, использующий предварительно инициализированное заданное значение.Initializes a new instance of the Lazy<T> class that uses a preinitialized specified value.

public:
 Lazy(T value);
public Lazy (T value);
new Lazy<'T> : 'T -> Lazy<'T>
Public Sub New (value As T)

Параметры

value
T T T T

Предварительно инициализированное значение для использования.The preinitialized value to be used.

Комментарии

Экземпляр, созданный этим конструктором используется несколькими потоками одновременно.An instance created with this constructor is usable by multiple threads concurrently.

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

Инициализирует новый экземпляр класса Lazy<T>.Initializes a new instance of the Lazy<T> class. При неактивной инициализации используются заданные функция и режим инициализации.When lazy initialization occurs, the specified initialization function and initialization mode are used.

public:
 Lazy(Func<T> ^ valueFactory, bool isThreadSafe);
public Lazy (Func<T> valueFactory, bool isThreadSafe);
new Lazy<'T> : Func<'T> * bool -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T), isThreadSafe As Boolean)

Параметры

valueFactory
Func<T>

Делегат, вызываемый для получения неактивно инициализированного значения, когда оно требуется.The delegate that is invoked to produce the lazily initialized value when it is needed.

isThreadSafe
Boolean Boolean Boolean Boolean

Значение true, если необходимо разрешить параллельное использование этого экземпляра несколькими потоками; значение false, если необходимо разрешить одновременное использование этого экземпляра только одним потоком.true to make this instance usable concurrently by multiple threads; false to make this instance usable by only one thread at a time.

Исключения

Примеры

Ниже приведен пример использования этого конструктора для предоставления отложенной инициализации с исключением, кэширование, в сценарии с одним потоком.The following example demonstrates the use of this constructor to provide lazy initialization with exception caching, in a scenario with a single thread. Он также демонстрирует использование Lazy<T> конструктор (указание LazyThreadSafetyMode.None для mode).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.

Примечание

Для кода, который демонстрирует, как использовать этот конструктор в сценариях с несколькими потоками (указание true для isThreadSafe), см. в примере Lazy<T>(Func<T>) конструктор.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.

В этом примере определяется класс LargeObject, для которого будет выполняться отложенная инициализация одним из нескольких потоков.The example defines a LargeObject class that will be initialized lazily by one of several threads. Три основные части кода, иллюстрируют Создание инициализатор, фактическую инициализацию и конструктор LargeObject класс, который демонстрирует кэширование исключений.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. В начале метода Main в этом примере создается потокобезопасный отложенный инициализатор для класса LargeObject:At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:

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);
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, False)

' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line: 
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.None)

В вызове конструктора isThreadSafe параметр false, поэтому Lazy<T> не является потокобезопасным.In the call to the constructor, the isThreadSafe parameter is false, so the Lazy<T> is not thread safe. Так как он не является потокобезопасным, в примере вызывается Value свойство три раза в одном потоке:Because it's not thread safe, the example calls the Value property three times on the same thread:

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);
    }
}
For i As Integer = 0 To 2
    Try
        Dim large As LargeObject = lazyLargeObject.Value
        large.Data(11) = 89
    Catch aex As ApplicationException
        Console.WriteLine("Exception: {0}", aex.Message)
    End Try
Next i

В конструкторе класса LargeObject , третий ключа раздела кода создает исключение первом LargeObject экземпляр создается, но после этого позволяет создавать экземпляр возникает: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:

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);
}
Private Shared pleaseThrow As Boolean = True
Public Sub New()
    If pleaseThrow Then
        pleaseThrow = False
        Throw New ApplicationException("Throw only ONCE.")
    End If

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

Если пример выполняется, первая попытка создать экземпляр LargeObject завершается ошибкой и исключение перехватывается.When the example is run, the first attempt to create an instance of LargeObject fails, and the exception is caught. Можно предположить, что следующая попытка будет выполнено успешно, но Lazy<T> объект в кэш исключение.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.

Примечание

Для простоты в этом примере используется глобальный экземпляр класса Lazy<T>, а все методы объявлены как static (Shared в Visual Basic).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.

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
 */
Imports System
Imports System.Threading

Friend Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    Private Shared Function InitLargeObject() As LargeObject
        Return New LargeObject()
    End Function


    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, False)

        ' The following lines show how to use other constructors to achieve exactly the
        ' same result as the previous line: 
        'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.None)


        Console.WriteLine(vbCrLf _
            & "LargeObject is not created until you access the Value property of the lazy" _
            & vbCrLf & "initializer. Press Enter to create LargeObject (three tries).")
        Console.ReadLine()

        For i As Integer = 0 To 2
            Try
                Dim large As LargeObject = lazyLargeObject.Value
                large.Data(11) = 89
            Catch aex As ApplicationException
                Console.WriteLine("Exception: {0}", aex.Message)
            End Try
        Next i

        Console.WriteLine(vbCrLf & "Press Enter to end the program")
        Console.ReadLine()
    End Sub
End Class

Friend Class LargeObject
    Private Shared pleaseThrow As Boolean = True
    Public Sub New()
        If pleaseThrow Then
            pleaseThrow = False
            Throw New ApplicationException("Throw only ONCE.")
        End If

        Console.WriteLine("LargeObject was created on thread id {0}.", _
            Thread.CurrentThread.ManagedThreadId)
    End Sub
    Public Data(100000000) As Long
End Class

' 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
' 

Комментарии

Потокобезопасный режим из Lazy<T> экземпляр, который инициализируется этим конструктором LazyThreadSafetyMode.ExecutionAndPublication Если isThreadSafetrue; в противном случае используется режим LazyThreadSafetyMode.None.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. Режим потокобезопасности описывает поведение, когда несколько потоков пытаются инициализировать Lazy<T> экземпляра.The thread safety mode describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Чтобы указать LazyThreadSafetyMode.PublicationOnly режиме Lazy<T>(Func<T>, LazyThreadSafetyMode) или Lazy<T>(LazyThreadSafetyMode) конструктор.To specify the LazyThreadSafetyMode.PublicationOnly mode, use the Lazy<T>(Func<T>, LazyThreadSafetyMode) or Lazy<T>(LazyThreadSafetyMode) constructor.

Исключения, вызываемые по valueFactory кэшируются.Exceptions that are thrown by valueFactory are cached. Дополнительные сведения см. в описании класса Lazy<T> или перечисления System.Threading.LazyThreadSafetyMode.For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

Дополнительно

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

Инициализирует новый экземпляр класса Lazy<T>, который использует заданную функцию инициализации и потокобезопасный режим.Initializes a new instance of the Lazy<T> class that uses the specified initialization function and thread-safety mode.

public:
 Lazy(Func<T> ^ valueFactory, System::Threading::LazyThreadSafetyMode mode);
public Lazy (Func<T> valueFactory, System.Threading.LazyThreadSafetyMode mode);
new Lazy<'T> : Func<'T> * System.Threading.LazyThreadSafetyMode -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T), mode As LazyThreadSafetyMode)

Параметры

valueFactory
Func<T>

Делегат, вызываемый для получения неактивно инициализированного значения, когда оно требуется.The delegate that is invoked to produce the lazily initialized value when it is needed.

mode
LazyThreadSafetyMode LazyThreadSafetyMode LazyThreadSafetyMode LazyThreadSafetyMode

Одно из значений перечисления, задающее потокобезопасный режим.One of the enumeration values that specifies the thread safety mode.

Исключения

Параметр mode содержит недопустимое значение.mode contains an invalid value.

Примеры

Ниже приведен пример использования этого конструктора для создания отложенный инициализатор, который позволяет нескольким потокам состязаются за право отложенного создания объекта.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. Кроме того, в примере показано, что исключения не кэшируются при указании LazyThreadSafetyMode.PublicationOnly, даже если инициализация выполняется с помощью функции, а не конструктором по умолчанию неактивно созданного типа.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 default constructor of the lazily created type.

Примечание

Пример, в котором показано, как использовать этот конструктор в однопоточных сценариях (указание LazyThreadSafetyMode.None для mode), см. в разделе Lazy<T>(Boolean) конструктор.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. Пример, демонстрирующий этот конструктор используется для предоставления блокировки вместо состояния гонки в сценариях с несколькими потоками (указание LazyThreadSafetyMode.ExecutionAndPublication для mode), см. в разделе Lazy<T>() конструктор.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.

В примере определяется LargeObject класс, который будет выполняться отложенная инициализация одним из нескольких потоков.The example defines a LargeObject class that will be initialized lazily by any of several threads. Четыре основные разделы кода иллюстрируют Создание инициализатор, фактическую инициализацию, функцию инициализации и конструктора и метода завершения LargeObject класса.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. В начале Main метод, в примере создается Lazy<T> объект, который выполняет отложенной инициализации LargeObject:At the beginning of the Main method, the example creates the Lazy<T> object that performs lazy initialization of the LargeObject:

lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, 
                             LazyThreadSafetyMode.PublicationOnly);
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
     LazyThreadSafetyMode.PublicationOnly)

Функция отложенный инициализатор для выполнения инициализации.The lazy initializer uses a function to perform the initialization. В этом случае функция необходима, поскольку нет конструктора по умолчанию для LargeObject класса.In this case, a function is required because there is no default constructor for the LargeObject class.

В примере создает и запускает три потока, которые блокируют на ManualResetEvent объекта, так что пример может освободить потоков за один раз.The example creates and starts three threads that block on a ManualResetEvent object, so that the example can release the threads all at once. В ThreadProc метод, который используется для всех трех потоков, вызвав Value создает свойство LargeObject экземпляр:In the ThreadProc method that's used by all three threads, calling the Value property creates the LargeObject instance:

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);
}
Dim large As LargeObject = Nothing
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.)
    SyncLock 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))
    End SyncLock
Catch ex As ApplicationException
    Console.WriteLine("ApplicationException: {0}", ex.Message)
End Try

В третьем ключа раздела кода, функция отложенной инициализации вызывается для создания LargeObject экземпляра.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:

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);
}
Private Shared instanceCount As Integer = 0
Private Shared Function InitLargeObject() As LargeObject
    If 1 = Interlocked.Increment(instanceCount) Then
        Throw New ApplicationException( _
            "Lazy initialization function failed on thread " & _
            Thread.CurrentThread.ManagedThreadId & ".")
    End If
    Return New LargeObject(Thread.CurrentThread.ManagedThreadId)
End Function

Для любого другого LazyThreadSafetyMode параметр необработанного исключения в функции инициализации будет кэшироваться.With any other LazyThreadSafetyMode setting, an unhandled exception in the initialization function would be cached. Тем не менее LazyThreadSafetyMode.PublicationOnly отключает кэширование исключений.However, LazyThreadSafetyMode.PublicationOnly suppresses exception caching. Выходные данные примера показано, что повторная попытка инициализировать объект завершается успешно.The output from the example demonstrates that a subsequent attempt to initialize the object succeeds.

Примечание

После сообщения о том, что другие потоки успешно инициализирован объект обычно отображается сообщение об исключении.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.

Так как конструктор для Lazy<T> указанный экземпляр LazyThreadSafetyMode.PublicationOnly, все три потока разрешено создавать LargeObject экземпляров.Because the constructor for the Lazy<T> instance specified LazyThreadSafetyMode.PublicationOnly, all three threads are allowed to create LargeObject instances. Это продемонстрировано в примере путем отображения сообщения консоли, в конструкторе и в методе завершения LargeObject класса:The example demonstrates this by displaying console messages in the constructor and in the finalizer of the LargeObject class:

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 Sub New(ByVal initializedBy As Integer)
    initBy = initializedBy
    Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub

Protected Overrides Sub Finalize()
    Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub

Lazy<T> Объект гарантирует, что только один экземпляр используется всеми потоками (за исключением самого потока, где функция инициализации вызывает исключение).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.

Примечание

Для простоты в этом примере используется глобальный экземпляр класса Lazy<T>, а все методы объявлены как static (Shared в Visual Basic).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.

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
 */
Imports System
Imports System.Threading

Friend Class Program
    Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing

    ' Factory function for lazy initialization.
    Private Shared instanceCount As Integer = 0
    Private Shared Function InitLargeObject() As LargeObject
        If 1 = Interlocked.Increment(instanceCount) Then
            Throw New ApplicationException( _
                "Lazy initialization function failed on thread " & _
                Thread.CurrentThread.ManagedThreadId & ".")
        End If
        Return New LargeObject(Thread.CurrentThread.ManagedThreadId)
    End Function

    Shared Sub Main()
        ' The lazy initializer is created here. LargeObject is not created until the 
        ' ThreadProc method executes.
        lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
             LazyThreadSafetyMode.PublicationOnly)


        ' Create and start 3 threads, passing the same blocking event to all of them.
        Dim startingGate As New ManualResetEvent(False)
        Dim threads() As Thread = { _
            New Thread(AddressOf ThreadProc), _
            New Thread(AddressOf ThreadProc), _
            New Thread(AddressOf ThreadProc) _
        }
        For Each t As Thread In threads
            t.Start(startingGate)
        Next t

        ' 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.)
        For Each t As Thread In threads
            t.Join()
        Next t

        Console.WriteLine(vbCrLf & _
            "Threads are complete. Running GC.Collect() to reclaim extra instances.")

        GC.Collect()

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

        Console.WriteLine(vbCrLf & "Note that only one instance of LargeObject was used.")
        Console.WriteLine("Press Enter to end the program")
        Console.ReadLine()
    End Sub


    Private Shared Sub ThreadProc(ByVal state As Object)
        ' Wait for the signal.
        Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
        waitForStart.WaitOne()

        Dim large As LargeObject = Nothing
        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.)
            SyncLock 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))
            End SyncLock
        Catch ex As ApplicationException
            Console.WriteLine("ApplicationException: {0}", ex.Message)
        End Try
    End Sub
End Class

Friend Class LargeObject
    Private initBy As Integer = -1
    Public ReadOnly Property InitializedBy() As Integer
        Get
            Return initBy
        End Get
    End Property

    Public Sub New(ByVal initializedBy As Integer)
        initBy = initializedBy
        Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
    End Sub

    Protected Overrides Sub Finalize()
        Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
    End Sub

    Public Data(99999999) As Long
End Class

' This example produces output similar to the following:
'
'Constructor: Instance initializing on thread 4
'ApplicationException: Lazy initialization function failed 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.
'
'Threads are complete. Running GC.Collect() to reclaim extra instances.
'Finalizer: Instance was initialized on 5
'
'Note that only one instance of LargeObject was used.
'Press Enter to end the program
'
'Finalizer: Instance was initialized on 4
' 

Комментарии

Потокобезопасный режим из Lazy<T> экземпляр описывает поведение, когда несколько потоков пытаются инициализировать Lazy<T> экземпляра.The thread safety mode of a Lazy<T> instance describes the behavior when multiple threads try to initialize the Lazy<T> instance.

Исключения, вызываемые по valueFactory кэшируются, если не mode является LazyThreadSafetyMode.PublicationOnly.Exceptions that are thrown by valueFactory are cached, unless mode is LazyThreadSafetyMode.PublicationOnly. Дополнительные сведения см. в описании класса Lazy<T> или перечисления System.Threading.LazyThreadSafetyMode.For more information, see the Lazy<T> class or the System.Threading.LazyThreadSafetyMode enumeration.

Дополнительно

Применяется к