【问题标题】:Why C# lambda expression can't use instance properties and fields?为什么 C# lambda 表达式不能使用实例属性和字段?
【发布时间】:2015-05-26 06:53:11
【问题描述】:

为什么 C# lambda 表达式不能使用实例属性和字段,什么时候在类作用域中使用?看这个例子:

public class Point:INotifyPropertyChanged
{
    public float X {get; set;}
    public float Y {get; set;}

    PropertyChangedEventHandler onPointsPropertyChanged =  (_, e)  =>
                               {
                                   X = 5;
                                   Y = 5; //Trying to access instace properties, but a compilation error occurs
                               };
    ...
}

为什么不允许这样做?

编辑

如果我们能做到:

public class Point:INotifyPropertyChanged
{
    public float X {get; set;}
    public float Y {get; set;}

    PropertyChangedEventHandler onPointsPropertyChanged; 
    public Point()
    {
        onPointsPropertyChanged =  (_, e)  =>
                               {
                                   X = 5;
                                   Y = 5;    
                               };
    }
    ...
}

为什么我们不能像类范围内的其他字段一样初始化onPointsPropertyChanged?例如:int a = 5onPointsPropertyChanged 字段将在构造函数执行后始终使用。

【问题讨论】:

  • 该字段在调用初始化程序时绑定到 this.X 和 this.Y,因此如果它们不可用,则它不起作用。直到构造函数执行之后,您才使用 onPointsPropertyChanged 并不重要。

标签: c# lambda scope


【解决方案1】:

您不能在其构造函数运行之前访问对象实例(例如在字段初始化程序或基构造函数调用中)。

在 lambda 内部和 lambda 外部都是如此。

C# had a bug 在某些情况下允许这样做。

【讨论】:

  • 但是,例如,在一个属性中,您可以访问其他属性和字段。不一样吗?您可以假设 lambda 范围在构造函数运行后有效。
  • @RaulOtaño 属性实际上是一种方法 - 这是一个 字段,因此适用字段初始化规则。
【解决方案2】:

字段初始化器不能引用非静态字段、方法或属性...

字段初始值设定项在构造函数执行之前执行。在构造函数执行之前,你不能引用任何字段或属性。

更改您的初始化以在您的类构造函数中设置 lambda 函数:

public class Point : INotifyPropertyChanged
{
  public float X { get; set; }
  public float Y { get; set; }

  PropertyChangedEventHandler onPointsPropertyChanged;

  public Point()
  {
    onPointsPropertyChanged = (_, e) =>
    {
      X = 5;
      Y = 5;
    };
  }
}

【讨论】:

  • onPointsPropertyChanged是类字段,那为什么声明的时候不能初始化,像普通字段一样:比如int a =5?
  • @RaulOtaño,声明时可以初始化。但是您还不能访问this.Xthis.Y。如果你说int a = [some non-static field or property] 也是一样
  • 当编译器构建它的表达式树时,它需要引用this 才能引用XY。在初始化的时候,变量this还不存在。 this 不存在于实例方法(例如非静态方法或构造函数)的范围之外。
  • @Matt Houser,现在更清楚了。我可以假设是因为它更容易实现。例如,编译器会假定 lambda 主体的范围与实例方法相同,而不是创建静态范围。
  • @RaulOtaño,我怀疑这条规则的动机与其说是为了便于实现编译器,不如说是不想让您访问部分初始化的类。您正在尝试做的是访问尚未完成运行其所有字段初始值设定项的类的属性。这意味着该类可能处于不一致的状态。
【解决方案3】:

你指的是什么实例?在您创建 lambda 表达式时,尚未创建任何实例;那么这些对 X 和 Y 的调用会绑定到什么实例?

【讨论】:

  • 实际上,此时确实存在一个实例。必须为他分配的字段创建一个实例才能存在。
  • 不,此时正在创建一个实例。它还不存在,并且不能被任何字段初始化器引用。
  • 在初始化期间不允许引用对象实例并不意味着它不存在。对象被创建,然后被初始化,然后就可以访问了。
  • 没错。在初始化之前,您无法访问该对象。因此,您无法在初始化期间访问它。
  • 不能访问不代表它不存在。它存在,但当时无法访问。
猜你喜欢
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 2015-12-09
  • 1970-01-01
  • 2011-06-16
  • 2018-06-11
  • 2011-11-23
  • 2017-03-21
相关资源
最近更新 更多