我有这样的代码:
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飞碟双向的答案 。
你可以将它移动到构造函数:
private Lazy<int> lazyGetSum;
public MyClass()
{
lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}
请参阅下面@JohnSkeet回答这个问题的原因,更多的细节。 访问经由懒非静态成员<T>或任何lambda表达式
这是你的问题的一个简化版本:
class Foo
{
int x = 10;
int y = this.x;
}
和稍微少简化之一:
class Foo
{
int x = 10;
Func<int> y = () => this.x;
}
(在this
通常是隐含的,但我将它明确这里清楚起见。)
在第一种情况下,使用this
是非常明显的。
在第二种情况下,它是稍微不太明显,因为它是由于lambda表达式推迟。 它仍然不是,虽然允许的......因为编译器将尝试建立它使用了代表this
为目标,就像这样:
class Foo
{
int x = 10;
Func<int> y = this.GeneratedMethod;
private int GeneratedMethod()
{
return x;
}
}
这是由C#5规范的部分10.5.5.2禁止:
对于实例字段变量初始值不能引用被创建的实例。
最简单的解决方法是只把初始化在构造函数体, 你可以参考这里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; } }
}
请注意,我已经简化lambda表达式以及-这是很少值得使用new Func<int>(...)
该错误是告诉你什么是错的。 你不能在一个字段初始访问属性。
假设你的类是这样的:
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));
}
}
我认为你需要定义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; } }
}
当然,你需要初始化你的领域。 你不能用其他的方式做到这一点。
编辑 :或者你可以用你的构造函数定义中没有任何定义static
。
public MyClass()
{
lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}
同
private Lazy<int> lazyGetSum;
public int Sum { get { return lazyGetSum.Value; } }
如果你想使用非静态方法。 你也可以使用一个为懒惰打造另类自认为得到函数功能参数在.value的,而不是在想偷懒的构造。
你的代码应该是这样的:
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); } }
}
它实现了在属性的属性。 只是,你可能会期望它,
发现这个问题时,我也有类似的问题,并希望找到一个很好的模式来使用。
与“移动初始化到构造”在其他的答案提出的问题是,在初始化函数的拉姆达现在出现在构造函数(和的确是一个明确的构造函数是在一个没有以前需要一个一类,现在需要)。
罚款这个玩具的例子,但在很多属性更复杂的类,它是有关于物业在一个地方所有的逻辑电路。
亚历克斯Siepman的回答表明,一个整洁的选择,但第三方网站托管LazyValue<>
类似乎是“服务不可用”,现在,在任何情况下,我不是在找一个第三方的解决方案,仅仅是一种有效的方式使用与正常Lazy<>
类。 我还担心,在一些使用情况下,创建委托实例,每个访问该属性可能是不平凡的时间相关闭合。
其在构造线似乎是不可避免的,因为在其他的答案中的各种问题,但似乎最好我避免把财产逻辑构造本身,因为它会被这么远的财产在任何的diff等分离
以下2种模式似乎工作,但我不知道是否有一个更好的替代我错过了。
模式1:使用Lambda不要打扰 - 下一个声明实函数的性质,并在一个隐含的委托包装它:
public class MyClass
{
public MyClass()
{
lazyGetSum = new Lazy<int>(GetSum);
}
public int X { get; set; }
public int Y { get; set; }
private Lazy<int> lazyGetSum;
public int Sum { get { return lazyGetSum.Value; } }
private int GetSum() { return X + Y; }
}
模式2:声明属性初始化函数和调用从构造。
public class MyClass
{
public MyClass()
{
LazyGetSumInit();
}
public int X { get; set; }
public int Y { get; set; }
private Lazy<int> lazyGetSum;
public int Sum { get { return lazyGetSum.Value; } }
private void LazyGetSumInit() { lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y)); }
}
通过侧看两个方面,我想我更喜欢第二个,除了对功能看似笨拙的名称。
[在我真正的实现中,我也有类似的名字InitSum
,所以它的它的“懒”属性的实现细节,它可以在原则上懒惰和非延迟执行之间改变,而不改变构造函数代码]