访问经由懒非静态构件 或任何lambda表达式(Accessing a non-static

2019-08-04 15:59发布

我有这样的代码:

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飞碟双向的答案 。

Answer 1:

你可以将它移动到构造函数:

private Lazy<int> lazyGetSum;
public MyClass()
{
   lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}

请参阅下面@JohnSkeet回答这个问题的原因,更多的细节。 访问经由懒非静态成员<T>或任何lambda表达式



Answer 2:

这是你的问题的一个简化版本:

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>(...)



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

}


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

当然,你需要初始化你的领域。 你不能用其他的方式做到这一点。

编辑 :或者你可以用你的构造函数定义中没有任何定义static

public MyClass()
    {
        lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    }

private Lazy<int> lazyGetSum; 
public int Sum { get { return lazyGetSum.Value; } }


Answer 5:

如果你想使用非静态方法。 你也可以使用一个为懒惰打造另类自认为得到函数功能参数在.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); } }
}

它实现了在属性的属性。 只是,你可能会期望它,



Answer 6:

发现这个问题时,我也有类似的问题,并希望找到一个很好的模式来使用。

与“移动初始化到构造”在其他的答案提出的问题是,在初始化函数的拉姆达现在出现在构造函数(和的确是一个明确的构造函数是在一个没有以前需要一个一类,现在需要)。

罚款这个玩具的例子,但在很多属性更复杂的类,它是有关于物业在一个地方所有的逻辑电路。

亚历克斯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 ,所以它的它的“懒”属性的实现细节,它可以在原则上懒惰和非延迟执行之间改变,而不改变构造函数代码]



文章来源: Accessing a non-static member via Lazy or any lambda expression