Подтвердить что ты не робот

Почему Lazy <T> ограничен статическими контекстами?

Я хотел бы использовать Lazy T для реализации memoization, но для функции инициализации требуется статический контекст.

Например, следующий код отказывается компилировать, предупреждая, что нестатические члены a и b недоступны. Мне непонятно, почему это так, так как объект Lazy является самим экземпляром и не имеет видимости в статическом контексте.

public class SomeExpensiveCalculation
{
    private int a;
    private int b;
    public Lazy<int> Result = new Lazy<int>(() => a + b); //nope!
}
4b9b3361

Ответ 1

Инициализаторы объектов вне конструктора (или метода) должны ссылаться только на статические члены. Это связано с тем, что экземпляр не был создан до тех пор, пока не будет запущен конструктор, поэтому поля еще не "готовы", и поэтому их нельзя ссылать. Статические поля работают, потому что они инициализируются перед полями.

Обратите внимание, что ошибка не вызвана Lazy<T>, она вызвана лямбда-выражением. Обходной путь (и правильный способ сделать это) состоит в инициализации Result в конструкторе.

Ответ 2

Я не знаю, почему ваш код не работает, но это должно работать:

    public class SomeExpensiveCalculation
    {
        private int a;
        private int b;
        public Lazy<int> Result;
        public SomeExpensiveCalculation()
        {
             Result = new Lazy<int>(() => a + b);
        }
    }

Ответ 3

Просто, чтобы расширить ответ на @Ondra, это можно использовать и с вложенным factory. Одно предостережение - опасайтесь относительных сроков жизни ленивых и factory:

public class SomeClass
{
  private readonly Lazy<ISomeDependency> _lazyField;

  // Ctor
  public SomeClass(ISomeFactory factory)
  {
     _lazyField = new Lazy<ISomeDependency>(() => factory.Create());
  }
}