Lazy<T> Класс

Определение

Обеспечивает поддержку неактивной инициализации.Provides support for lazy initialization.

generic <typename T>
public ref class Lazy
[System.Runtime.InteropServices.ComVisible(false)]
[System.Serializable]
public class Lazy<T>
type Lazy<'T> = class
Public Class Lazy(Of T)

Параметры типа

T

тип объекта, который неактивно инициализируется.The type of object that is being lazily initialized.

Наследование
Lazy<T>
Производный
Атрибуты

Примеры

В следующем примере показано использование Lazy<T> класса для обеспечения отложенной инициализации с доступом из нескольких потоков.The following example demonstrates the use of the Lazy<T> class to provide lazy initialization with access from multiple threads.

Примечание

В примере используется Lazy<T>(Func<T>) конструктор.The example uses the Lazy<T>(Func<T>) constructor. Также демонстрируется использование конструктора (с 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.

Пример, демонстрирующий кэширование исключений с помощью тех же конструкторов, см Lazy<T>(Func<T>) . в разделе Конструктор.For an example that demonstrates exception caching using the same constructors, see 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 four key sections of code illustrate the creation of the initializer, the factory method, the actual initialization, and the constructor of the LargeObject class, which displays a message when the object is created. В начале метода 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)

Метод Factory показывает создание объекта с заполнительом для дальнейшей инициализации:The factory method shows the creation of the object, with a placeholder for further initialization:

static LargeObject InitLargeObject()
{
    LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
    // Perform additional initialization here.
    return large;
}
Private Shared Function InitLargeObject() As LargeObject
    Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
    ' Perform additional initialization here.
    Return large
End Function

Обратите внимание, что первые два раздела кода можно объединить с помощью лямбда-функции, как показано ниже:Note that the first two code sections could be combined by using a lambda function, as shown here:

lazyLargeObject = new Lazy<LargeObject>(() => 
{
    LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
    // Perform additional initialization here.
    return large;
});
lazyLargeObject = New Lazy(Of LargeObject)(Function () 
    Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId) 
    ' Perform additional initialization here.
    Return large
End Function)

В этом примере приостанавливается, чтобы указать, что неопределенный период может пройти до возникновения отложенной инициализации.The example pauses, to indicate that an indeterminate period may elapse before lazy initialization occurs. При нажатии клавиши Ввод в примере создаются и запускаются три потока.When you press the Enter key, the example creates and starts three threads. Метод, используемый всеми тремя потоками, Value вызывает свойство. ThreadProcThe ThreadProc method that's used by all three threads calls the Value property. В первый раз происходит LargeObject создание экземпляра:The first time this happens, the LargeObject instance is created:

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]);
}
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

Конструктор LargeObject класса, который включает последний ключевой раздел кода, отображает сообщение и записывает идентификатор инициализации потока.The constructor of the LargeObject class, which includes the last key section of code, displays a message and records the identity of the initializing thread. Выходные данные программы отображаются в конце полного листинга кода.The output from the program appears at the end of the full code listing.

int initBy = 0;
public LargeObject(int initializedBy)
{
    initBy = initializedBy;
    Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
Private initBy As Integer = 0
Public Sub New(ByVal initializedBy As Integer)
    initBy = initializedBy
    Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub

Примечание

Для простоты в этом примере используется глобальный экземпляр класса 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()
    {
        LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
        // Perform additional initialization here.
        return large;
    }
    

    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 uses LargeObject.
        Thread[] threads = new Thread[3];
        for (int i = 0; i < 3; i++)
        {
            threads[i] = new Thread(ThreadProc);
            threads[i].Start();
        }

        // Wait for all 3 threads to finish. 
        foreach (Thread t in threads)
        {
            t.Join();
        }

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


    static void ThreadProc(object state)
    {
        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]);
        }
    }
}

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

    int initBy = 0;
    public LargeObject(int initializedBy)
    {
        initBy = initializedBy;
        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 3.
Initialized by thread 3; last used by thread 3.
Initialized by thread 3; last used by thread 4.
Initialized by thread 3; last used by thread 5.

Press Enter to end the program
 */
Imports System.Threading

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

    Private Shared Function InitLargeObject() As LargeObject
        Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
        ' Perform additional initialization here.
        Return large
    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 uses LargeObject.
        Dim threads(2) As Thread
        For i As Integer = 0 To 2
            threads(i) = New Thread(AddressOf ThreadProc)
            threads(i).Start()
        Next i

        ' Wait for all 3 threads to finish. 
        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)
        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
    End Sub
End Class

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

    Private initBy As Integer = 0
    Public Sub New(ByVal initializedBy As Integer)
        initBy = initializedBy
        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.
'
'LargeObject was created on thread id 3.
'Initialized by thread 3; last used by thread 3.
'Initialized by thread 3; last used by thread 5.
'Initialized by thread 3; last used by thread 4.
'
'Press Enter to end the program
' 

Комментарии

Используйте отложенную инициализацию, чтобы отложить создание большого или ресурсоемкиго объекта или выполнение ресурсоемких задач, особенно если такое создание или выполнение может не произойти в течение всего времени существования программы.Use lazy initialization to defer the creation of a large or resource-intensive object, or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program.

Чтобы подготовиться к отложенной инициализации, создайте экземпляр Lazy<T>.To prepare for lazy initialization, you create an instance of Lazy<T>. Аргумент типа создаваемого Lazy<T> объекта указывает тип объекта, который требуется инициализировать отложенно.The type argument of the Lazy<T> object that you create specifies the type of the object that you want to initialize lazily. Конструктор, используемый для создания Lazy<T> объекта, определяет характеристики инициализации.The constructor that you use to create the Lazy<T> object determines the characteristics of the initialization. Отложенная инициализация производится при первом обращении к свойству Lazy<T>.Value.Lazy initialization occurs the first time the Lazy<T>.Value property is accessed.

В большинстве случаев выбор конструктора зависит от ответов на два вопроса:In most cases, choosing a constructor depends on your answers to two questions:

  • Будет ли доступ к объекту с отложенной инициализацией осуществляться из более чем одного потока?Will the lazily initialized object be accessed from more than one thread? Если да, то Lazy<T> объект может создать его в любом потоке.If so, the Lazy<T> object might create it on any thread. Можно использовать один из простых конструкторов, поведением по умолчанию которых является создание потокобезопасного Lazy<T> объекта, чтобы создавался только один экземпляр объекта с отложенным созданием экземпляров, независимо от того, сколько потоков пытается получить к нему доступ.You can use one of the simple constructors whose default behavior is to create a thread-safe Lazy<T> object, so that only one instance of the lazily instantiated object is created no matter how many threads try to access it. Чтобы создать Lazy<T> объект, который не является потокобезопасным, необходимо использовать конструктор, который позволяет указать отсутствие потокобезопасности.To create a Lazy<T> object that is not thread safe, you must use a constructor that enables you to specify no thread safety.

    Внимание!

    Обеспечение безопасности Lazy<T> объектного потока не защищает объект с отложенной инициализацией.Making the Lazy<T> object thread safe does not protect the lazily initialized object. Если несколько потоков могут получить доступ к объекту с отложенной инициализацией, необходимо сделать его свойства и методы надежными для многопоточного доступа.If multiple threads can access the lazily initialized object, you must make its properties and methods safe for multithreaded access.

  • Если отложенная инициализация требует большого объема кода или если у отложенно инициализированного объекта есть конструктор без параметров, который выполняет все необходимые действия и не создает исключения?Does lazy initialization require a lot of code, or does the lazily initialized object have a parameterless constructor that does everything you need and doesn't throw exceptions? Если необходимо написать код инициализации или необходимо обработать исключения, используйте один из конструкторов, которые принимают фабричный метод.If you need to write initialization code or if exceptions need to be handled, use one of the constructors that takes a factory method. Напишите код инициализации в фабричном методе.Write your initialization code in the factory method.

В следующей таблице показано, какой конструктор выбрать в зависимости от этих двух факторов.The following table shows which constructor to choose, based on these two factors:

Доступ к объекту будет осуществлятьсяObject will be accessed by Если код инициализации не требуется (конструктор без параметров), используйтеIf no initialization code is required (parameterless constructor), use Если требуется код инициализации, используйтеIf initialization code is required, use
Несколько потоковMultiple threads Lazy<T>() Lazy<T>(Func<T>)
Один потокOne thread Lazy<T>(Boolean)с isThreadSafeпараметром. falseLazy<T>(Boolean) with isThreadSafe set to false. Lazy<T>(Func<T>, Boolean)с isThreadSafeпараметром. falseLazy<T>(Func<T>, Boolean) with isThreadSafe set to false.

Для указания фабричного метода можно использовать лямбда-выражение.You can use a lambda expression to specify the factory method. Это позволяет хранить весь код инициализации в одном месте.This keeps all the initialization code in one place. Лямбда-выражение фиксирует контекст, включая любые аргументы, передаваемые в конструктор отложенно инициализированного объекта.The lambda expression captures the context, including any arguments you pass to the lazily initialized object's constructor.

Кэширование исключений При использовании фабричных методов исключения кэшируются.Exception caching When you use factory methods, exceptions are cached. Это значит, что если метод фабрики создает исключение при первом обращении потока к Value свойству Lazy<T> объекта, то то же самое исключение возникает при каждой последующей попытке.That is, if the factory method throws an exception the first time a thread tries to access the Value property of the Lazy<T> object, the same exception is thrown on every subsequent attempt. Это гарантирует, что каждый вызов Value свойства приведет к одному и тому же результату и избежать незначительных ошибок, которые могут возникать, если разные потоки получают разные результаты.This ensures that every call to the Value property produces the same result and avoids subtle errors that might arise if different threads get different results. Он Lazy<T> означает фактическое T значение, которое в противном случае было бы инициализировано в более ранней точке, обычно во время запуска.The Lazy<T> stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. Сбой в более ранней точке обычно является неустранимой.A failure at that earlier point is usually fatal. Если есть вероятность возможного сбоя, рекомендуется создать логику повторных попыток в подпрограммы инициализации (в данном случае — фабричном методе), точно так же, как если бы вы не использовали отложенную инициализацию.If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.

Альтернатива блокировке В некоторых ситуациях может возникнуть необходимость избежать издержек, обусловленных Lazy<T> поведением блокировки по умолчанию объекта.Alternative to locking In certain situations, you might want to avoid the overhead of the Lazy<T> object's default locking behavior. В редких ситуациях возможны взаимоблокировки.In rare situations, there might be a potential for deadlocks. В таких случаях можно использовать Lazy<T>(LazyThreadSafetyMode) конструктор или Lazy<T>(Func<T>, LazyThreadSafetyMode) и указать LazyThreadSafetyMode.PublicationOnly.In such cases, you can use the Lazy<T>(LazyThreadSafetyMode) or Lazy<T>(Func<T>, LazyThreadSafetyMode) constructor, and specify LazyThreadSafetyMode.PublicationOnly. Это позволяет Lazy<T> объекту создать копию отложенно инициализированного объекта в каждом из нескольких потоков, если потоки Value вызывают свойство одновременно.This enables the Lazy<T> object to create a copy of the lazily initialized object on each of several threads if the threads call the Value property simultaneously. Lazy<T> Объект гарантирует, что все потоки будут использовать один и тот же экземпляр объекта с отложенной инициализацией и отбрасывают неиспользуемые экземпляры.The Lazy<T> object ensures that all threads use the same instance of the lazily initialized object and discards the instances that are not used. Таким образом, стоимость снижения затрат на блокировку заключается в том, что программа может иногда создавать и удалять дополнительные копии дорогостоящего объекта.Thus, the cost of reducing the locking overhead is that your program might sometimes create and discard extra copies of an expensive object. В большинстве случаев это маловероятно.In most cases, this is unlikely. Примеры для Lazy<T>(LazyThreadSafetyMode) конструкторов и Lazy<T>(Func<T>, LazyThreadSafetyMode) демонстрируют это поведение.The examples for the Lazy<T>(LazyThreadSafetyMode) and Lazy<T>(Func<T>, LazyThreadSafetyMode) constructors demonstrate this behavior.

Важно!

При указании LazyThreadSafetyMode.PublicationOnlyисключения никогда не кэшируются, даже если указан фабричный метод.When you specify LazyThreadSafetyMode.PublicationOnly, exceptions are never cached, even if you specify a factory method.

Эквивалентные конструкторы В дополнение к включению использования LazyThreadSafetyMode.PublicationOnly Lazy<T>(LazyThreadSafetyMode) конструкторы и Lazy<T>(Func<T>, LazyThreadSafetyMode) могут дублировать функциональность других конструкторов.Equivalent constructors In addition to enabling the use of LazyThreadSafetyMode.PublicationOnly, the Lazy<T>(LazyThreadSafetyMode) and Lazy<T>(Func<T>, LazyThreadSafetyMode) constructors can duplicate the functionality of the other constructors. В следующей таблице приведены значения параметров, которые создают эквивалентное поведение.The following table shows the parameter values that produce equivalent behavior.

Создание Lazy<T> объекта, которыйTo create a Lazy<T> object that is Для конструкторов, имеющих LazyThreadSafetyMode mode параметр, задайте для mode значениеFor constructors that have a LazyThreadSafetyMode mode parameter, set mode to Для конструкторов, имеющих логический isThreadSafe параметр, задайте для значение isThreadSafeFor constructors that have a Boolean isThreadSafe parameter, set isThreadSafe to Для конструкторов без параметров безопасности потокаFor constructors with no thread safety parameters
Полностью потокобезопасный; использует блокировку, чтобы гарантировать, что только один поток инициализирует значение.Fully thread safe; uses locking to ensure that only one thread initializes the value. ExecutionAndPublication true Все такие конструкторы являются полностью потокобезопасными.All such constructors are fully thread safe.
Не является потокобезопасным.Not thread safe. None false Неприменимо.Not applicable.
Полностью потокобезопасный; потоки, которые инициализируют значение.Fully thread safe; threads race to initialize the value. PublicationOnly Неприменимо.Not applicable. Неприменимо.Not applicable.

Другие возможности Сведения об использовании Lazy<T> с полями static потока или в качестве резервного хранилища для свойств см. в разделе Отложенная инициализация.Other capabilities For information about the use of Lazy<T> with thread-static fields, or as the backing store for properties, see Lazy Initialization.

Конструкторы

Lazy<T>()

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

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

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

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

Lazy<T>(LazyThreadSafetyMode)

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

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

Свойства

IsValueCreated

Получает значение, указывающее, было ли создано значение для данного экземпляра Lazy<T>.Gets a value that indicates whether a value has been created for this Lazy<T> instance.

Value

Получает неактивно инициализированное значение текущего экземпляра Lazy<T>.Gets the lazily initialized value of the current Lazy<T> instance.

Методы

Equals(Object)

Определяет, равен ли заданный объект текущему объекту.Determines whether the specified object is equal to the current object.

(Унаследовано от Object)
GetHashCode()

Служит хэш-функцией по умолчанию.Serves as the default hash function.

(Унаследовано от Object)
GetType()

Возвращает объект Type для текущего экземпляра.Gets the Type of the current instance.

(Унаследовано от Object)
MemberwiseClone()

Создает неполную копию текущего объекта Object.Creates a shallow copy of the current Object.

(Унаследовано от Object)
ToString()

Создает и возвращает строковое представление свойства Value данного экземпляра.Creates and returns a string representation of the Value property for this instance.

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

Потокобезопасность

По умолчанию все открытые и защищенные члены Lazy<T> класса являются потокобезопасными и могут использоваться одновременно из нескольких потоков.By default, all public and protected members of the Lazy<T> class are thread safe and may be used concurrently from multiple threads. Эти гарантии безопасности потоков могут быть удалены дополнительно и для каждого экземпляра с помощью параметров для конструкторов типа.These thread-safety guarantees may be removed optionally and per instance, using parameters to the type's constructors.

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