Может кто-нибудь объяснить простыми словами, почему Lazy в C # должен получить Func?

public Lazy (Func<T> valueFactory);

Я понимаю, что иногда вам нужна функция для того, чтобы сделать init () .
однако, часто я пишу синглтон или что-то простое, где просто создаю новый экземпляр класса. Как показано в книге Скита Джона. http://csharpindepth.com/Articles/General/Singleton.aspx

Я нахожу этот синтаксис очень раздражающим.

Благодарность!

private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
2
Gilad 21 Авг 2018 в 11:52

4 ответа

Лучший ответ

Вы не можете заставить Lazy работать без функции инициализатора. Таким образом, он обеспечивает логику создания объекта, но еще не вызван.

Учти это:

new Lazy<Singleton>(new Singleton());

Это уже создает новый Singleton. Там нет смысла для ленивых больше. Функция позволяет Lazy<T> создавать объект в любое время в будущем.

Еще один плюс для Func<T> заключается в том, что он не должен быть новым объектом, который он создает. Это может быть что-нибудь еще. Это может быть многострочное утверждение, выборка чего-то еще и т. Д.

Я могу поспорить, что одна оптимизация заключается в том, что new Lazy<T>() будет использовать new() в T, что исключает необходимость вызова конструктора. Однако это невозможно с текущим синтаксисом, но он работает со статическим фабричным методом.

Примерно так (и да, это в основном то, что вы делаете сейчас, но потом спрятано в ядро):

public static class LazyDefault
{
    public static Lazy<TNew> New<TNew>() where TNew : new()
    {
        return new Lazy<TNew>(() => new TNew());
    }
}

Или, как предложил CodeCaster с производным классом:

public class SuperLazy<T> : Lazy<T>
    where T : new()
{
    public SuperLazy()
         : base(() => new T())
    {
    }
}
6
Patrick Hofman 21 Авг 2018 в 09:01

Вам нужен функционал, потому что если бы вы могли сделать это:

var Lazy<Foo> = new Lazy<Foo>(new Foo());

Вы уже создаете экземпляр Foo, который вам не нужен, иначе вам не пришлось бы использовать Lazy<T> для начала.

Func<T> содержит инициализатор для Foo, но инициализирует его только при доступе к Lazy<T> Value.

5
CodeCaster 21 Авг 2018 в 08:56

То, что вы передаете конструктору Lazy<T>, называется thunk (Википедия ) :

В компьютерном программировании thunk - это подпрограмма, используемая для добавления дополнительных вычислений в другую подпрограмму. Thunks в основном используются для задержки вычислений до тех пор, пока не потребуется его результат, или для вставки операций в начало или конец другой подпрограммы. У них есть множество других приложений в генерации кода компилятора и модульном программировании.

То есть ядро ленивой оценки заключается в том, что все оцениваемое событие откладывается до тех пор, пока оно действительно не потребуется.

Если вас раздражает необходимость явно указывать Func<T>, вы можете упростить это следующим образом:

public static class Lazy 
{
     public static Lazy<T> Of<T>()
            where T : class, new() => new Lazy<T>(() => new T())
}


var lazyFoo = Lazy.Of<Foo>()
1
Matías Fidemraizer 21 Авг 2018 в 09:01

Lazy требуется Func для фактической инициализации внутреннего значения. вся цель использования Lazy - инициализировать значение только тогда, когда это необходимо. поэтому должен быть способ Lazy на самом деле инициализировать значение, когда это необходимо, вот где Func входит. Я не вижу другого способа реализовать что-то вроде Lazy, кроме передачи функции инициализации.

1
Shanaka Rusith 21 Авг 2018 в 09:03
51945003