Почему 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!
}
Ответы
Ответ 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());
}
}