通过Lazy <T>或任何lambda表达式访问非静态成员

Saw*_*wan 47 .net c# .net-4.0 lazy-evaluation

我有这个代码:

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; } }

}
Run Code Online (Sandbox Code Playgroud)

给我这个错误:

字段初始值设定项不能引用非静态字段,方法或属性.

我认为通过懒惰访问非静态成员是非常合理的,怎么做?

*编辑*

接受的答案完美地解决了这个问题,但是要看到问题的详细和深入 - 总是原因,你可以阅读Joh Skeet的答案.

Jle*_*HeP 77

您可以将其移动到构造函数中:

private Lazy<int> lazyGetSum;
public MyClass()
{
   lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}
Run Code Online (Sandbox Code Playgroud)

有关问题原因的详细信息,请参阅下面的@JohnSkeet答案. 通过Lazy <T>或任何lambda表达式访问非静态成员

  • 你受到了谴责:) http://meta.stackexchange.com/questions/17086/add-a-skeet-sniped-badge (3认同)
  • 是的,我的徽章在哪里?:) (2认同)
  • @MSakherSawan:你明白*为什么*它在构造函数体中起作用,而*为什么*它之前没有用? (2认同)

Jon*_*eet 58

这是您问题的简化版本:

class Foo
{
    int x = 10;
    int y = this.x;
}
Run Code Online (Sandbox Code Playgroud)

一个稍微简化的一个:

class Foo
{
    int x = 10;
    Func<int> y = () => this.x;
}
Run Code Online (Sandbox Code Playgroud)

(这this通常是含蓄的,但为了清楚起见,我在这里明确了这一点.)

在第一种情况下,使用this非常明显.

在第二种情况下,它稍微不那么明显,因为它由于lambda表达式而延迟.它仍然不被允许...因为编译器会尝试构建一个用作this目标的委托,如下所示:

class Foo
{
    int x = 10;
    Func<int> y = this.GeneratedMethod;

    private int GeneratedMethod()
    {
        return x;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是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; } }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我也简化了lambda表达式 - 它很少值得使用new Func<int>(...).

  • @MSakherSawan:我试图给你解决问题的方法*和*解释为什么这是一个问题开始...... (21认同)