5

Why C# lambda expression can't use instance properties and fields, when is used in a class scope? See this example:

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

Why this is not allowed?

EDIT

If we can do:

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

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

Why we can't initialize onPointsPropertyChanged like a other fields inside the class scope?, for instancie: int a = 5. The field onPointsPropertyChanged always will be used after the constructor execute.

1
  • The field is bound to this.X and this.Y when you call the initializer, so if they're not already available, it doesn't work. It doesn't matter that you aren't using onPointsPropertyChanged until after the constructor executes. Commented Jun 10, 2013 at 19:04

3 Answers 3

8

You cannot access an object instance before its constructor runs (such as in a field initializer or base constructor call).

This is true both inside a lambda and outside a lambda.

C# < 4 had a bug that allowed this in certain cases.

Sign up to request clarification or add additional context in comments.

2 Comments

But for instance, inside a property you can access other properties and fields. It is not the same? You can assume the lambda scope is valid after the constructor run.
@RaulOtaño A property is effectively a method - this is a field, so the field initializer rules apply.
6

A field initializer cannot reference the non-static field, method, or property ...

Field initializers are executed before the constructor is executed. You're not permitted to reference any fields or properties before the constructor is executed.

Change your initialization to set the lambda function in your classes contructor:

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

  PropertyChangedEventHandler onPointsPropertyChanged;

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

6 Comments

onPointsPropertyChanged is a class field, then why can not be initialized when declared, like a normal field: int a =5 for instance?
@RaulOtaño, It can be initialized when declared. But you can't access this.X and this.Y yet. The same would be true if you said int a = [some non-static field or property]
When the compiler is building it's expression tree, it needs a reference to this in order to reference X or Y. At the time of the initialization, the variable this does not exist yet. this does not exist outside the scope of an instance method (such as a non-static method or a constructor).
@Matt Houser, It is a bit more clear now. I can assume is because it is a bit more easy to implement. For instance, the compiler would assume the scope of the lambda's body, would be the same of an instance method, instead of to create a static scope.
@RaulOtaño, I suspect the motivation of this rule is less about ease of implementing the compiler than about not wanting you to access a partially-initialized class. What you are trying to do is access properties of a class that has not finished running all of its field initializers. That means the class could be in an inconsistent state.
|
-2

What instance are you referring to? At the point where you are creating the lambda expression, no instance has yet been created; so what instance would those calls to X and Y be bound to?

5 Comments

Actually, an instance does exist at that point. An instance has to have been created for the field he is assigning to to exist.
No, an instance is being created at that point. It does not yet exist, and cannot be referred to by any field initializers.
That you aren't allowed to refer to the object instance during its initialization doesn't mean it doesn't exist. The object is created, then it is initialized, and then it can be accessed.
Precisely. You cannot access the object until it has been initialized. Therefore, you cannot access it during initialization.
Just because you can't access it doesn't mean it doesn't exist. It exists, but just can't be accessed at that point in time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.