Доступ к нестационарному элементу через Lazy <T> или любое выражение лямбда
У меня есть этот код:
public class MyClass
{
public int X { get; set; }
public int Y { get; set; }
private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
public int Sum{ get { return lazyGetSum.Value; } }
}
Дает мне эту ошибку:
Инициализатор поля не может ссылаться на нестатические поля, метод или свойство.
Я думаю, что очень разумно обращаться к нестационарному члену через ленивый, как это сделать?
* РЕДАКТИРОВАТЬ *
Принятый ответ решает проблему отлично, но для того, чтобы увидеть подробный и подробный, и всегда - причину проблемы, вы можете прочитать ответ Joh Skeet.
Ответы
Ответ 1
Вы можете переместить его в конструктор:
private Lazy<int> lazyGetSum;
public MyClass()
{
lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}
См. ниже @JohnSkeet для получения более подробной информации о причине проблемы.
Доступ к нестатическому элементу через Lazy <T> или любое лямбда-выражение
Ответ 2
Вот упрощенная версия вашей проблемы:
class Foo
{
int x = 10;
int y = this.x;
}
И немного менее упрощенный:
class Foo
{
int x = 10;
Func<int> y = () => this.x;
}
(this
обычно неявно, но я сделал это явным для ясности.)
В первом случае использование this
очень очевидно.
Во втором случае это несколько менее очевидно, потому что оно откладывается из-за лямбда-выражения. Это все еще не разрешено, хотя... потому что компилятор попытается построить делегат, который использовал this
в качестве цели, например:
class Foo
{
int x = 10;
Func<int> y = this.GeneratedMethod;
private int GeneratedMethod()
{
return x;
}
}
Это запрещено в разделе 10.5.5.2 спецификации С# 5:
Инициализатор переменных для поля экземпляра не может ссылаться на создаваемый экземпляр.
Самое простое исправление - просто поместить инициализацию в тело конструктора, где вы можете обратиться к this
. Итак, в вашем коде:
public class MyClass
{
public int X { get; set; }
public int Y { get; set; }
private Lazy<int> lazyGetSum;
public MyClass()
{
lazyGetSum = new Lazy<int>(() => X + Y);
}
public int Sum{ get { return lazyGetSum.Value; } }
}
Обратите внимание, что я упростил также выражение лямбда - это очень редко стоит использовать new Func<int>(...)
.
Ответ 3
Ошибка говорит вам точно, что не так. Вы не можете получить доступ к свойству в полевом инициализаторе.
Предположим, что ваш класс похож:
public class MyClass
{
public int X { get; set; }
public int Y { get; set; }
private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => 2 + 3));
public int Sum { get { return lazyGetSum.Value; } }
}
Тогда он скомпилируется без каких-либо проблем. Поскольку в вашем коде вы получаете доступ к свойствам X и Y в инициализации поля. Вы получаете ошибку.
Вы также можете инициализировать их в конструкторе, если хотите:
public class MyClass
{
public int X { get; set; }
public int Y { get; set; }
private Lazy<int> lazyGetSum;
public int Sum { get { return lazyGetSum.Value; } }
public MyClass()
{
lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}
}
Ответ 4
Я думаю, вам нужно определить static
ваши поля, чтобы использовать его следующим образом:
public class MyClass
{
public static int X { get; set; }
public static int Y { get; set; }
private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
public int Sum { get { return lazyGetSum.Value; } }
}
И, конечно же, вам нужно инициализировать свои поля. Вы не можете сделать это другим способом.
EDIT. Или вы можете определить с помощью своего конструктора без любое определение static
.
public MyClass()
{
lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}
с
private Lazy<int> lazyGetSum;
public int Sum { get { return lazyGetSum.Value; } }
Ответ 5
Если вы хотите использовать нестатический метод. Вы также можете использовать построить альтернативу для Lazy, которая получает параметр Func в .Value, а не в конструкторе Lazy.
Код будет выглядеть так:
public class MyClass
{
public int X { get; set; }
public int Y { get; set; }
private readonly LazyValue<int> lazyGetSum = new LazyValue<int>();
public int Sum { get { return lazyGetSum.GetValue(() => X + Y); } }
}
Он реализует свойство в свойстве.. Там, где вы могли бы ожидать этого,