The = operator in fact does two things:

  • Set the field/property on the left-hand side to the value on the right-hand side.
  • Return the newly assigned value.

This is also the reason why statements like this work:

object item;
while ((item = getItem()) != null)   


It compiles because it's a valid Func<T, bool>. There's no way for the compiler to tell that in this case, it shouldn't allow that.


x => x.SomeBooleanProperty = true

This lambda means - for x, assign true to SomeBooleanProperty. The result of the assignment is the value true as well.

If this is changed to:

x => x.SomeBooleanProperty

The lambda means - for x return the value of SomeBooleanProperty.


Looks like the problem is related to the fact that

x => x.BooleanProperty = true

evaluates to true and is thus a valid where() predicate

I tried it with ints and was able to get the same behaviour.

public void Test_because_im_scared() {
    var falseProperty = new TestModel { BooleanProperty = false };
    var trueProperty = new TestModel { BooleanProperty = true };

    var list = new List<TestModel> { falseProperty, trueProperty };

    var results = list.Where(x => (x.IntProperty = 17) == 17) ;

    Assert.IsTrue(list.All(itm => itm.IntProperty == 0));

    //all fine so far, now evaluate the results 
    var evaluatedResults = results.ToList();

    Assert.IsTrue(list.All(itm => itm.IntProperty == 0)); // fails here, all 17


private class TestModel {
   public bool BooleanProperty { get; set; }
   public int IntProperty { get; set; }

AFAIK this is unintended behaviour, the IEnumerable<> extensions should all return new enumerables and not change the original but I have not seen that guaranteed anywhere.

It looks like it could be used as a pseudo foreach() but I wouldn't recommend it :-/


Related Articles