← Все вопросы

Как работает Lazy<T> и когда его применять?

Задан 20 месяцев назад595 просмотров3 ответа
8

Хочу, чтобы тяжёлый объект создавался только при первом обращении. Слышал про Lazy<T>, но не до конца понял, как он работает и потокобезопасен ли он.

Lazy<int> value = new Lazy<int>(() => Compute());

3 ответа

13
✓ Принятый ответ — помог автору

Lazy<T> откладывает создание объекта до первого обращения к свойству .Value. Фабрика вызывается ровно один раз, результат кэшируется.

Lazy<int> lazy = new Lazy<int>(() =>
{
    Console.WriteLine("Вычисляем...");
    return 42;
});

Console.WriteLine("До обращения"); // фабрика ещё не вызвана
Console.WriteLine(lazy.Value);     // "Вычисляем..." + 42
Console.WriteLine(lazy.Value);     // просто 42 (кэш)

Про потокобезопасность: по умолчанию (LazyThreadSafetyMode.ExecutionAndPublication) Lazy<T> потокобезопасен — даже при одновременном обращении из нескольких потоков фабрика выполнится один раз. Можно ослабить через конструктор с bool isThreadSafe или enum-режимом, если синхронизация не нужна.

Типичные сценарии: дорогая инициализация (загрузка конфига, подключение), синглтоны, разрыв тяжёлых зависимостей.

7

Удобный приём — ленивый синглтон:

public sealed class Config
{
    private static readonly Lazy<Config> _instance =
        new Lazy<Config>(() => new Config());
    public static Config Instance => _instance.Value;
    private Config() { /* тяжёлая загрузка */ }
}

Объект создастся при первом Config.Instance и будет потокобезопасным из коробки.

3

Осторожно с исключениями в фабрике: в режиме по умолчанию исключение кэшируется, и каждый следующий .Value будет выбрасывать его же. Если нужно повторять попытки — используйте LazyThreadSafetyMode.PublicationOnly.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект