3

我正在寻找关于为什么允许编译以下代码行的解释:

var results = someCollection.Where(x => x.SomeBooleanProperty = true);

注意使用单个相等运算符(可能开发人员处于 SQL 模式),这是一个很容易犯的错误。这会编译并在评估结果时(例如someCollection.ToList())将整个集合上的标志更改为 true!

如果您正在使用实体框架或任何其他 ORM,那么这可能会被检测为更改。我刚刚在生产代码中遇到了这个问题,但幸运的是它只是在只读屏幕上引起了一个小问题(但完全令人困惑)。试想一下,如果数据实际上是持久的,那么可能会导致可怕的逻辑和数据问题。

只是为了确保我没有发疯并且它确实改变了我编写的测试失败的数据:

[Test]
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.BooleanProperty = true);

    Assert.IsFalse(falseProperty.BooleanProperty);
    Assert.IsTrue(trueProperty.BooleanProperty);

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

    Assert.IsFalse(falseProperty.BooleanProperty);  //test fails here!
    Assert.IsTrue(trueProperty.BooleanProperty);
}
4

4 回答 4

9

=操作员实际上做了两件事:

  • 将左侧的字段/属性设置为右侧的值。
  • 返回新分配的值。

这也是为什么这样的陈述有效的原因:

object item;
while ((item = getItem()) != null)   
  processItem(item);
于 2012-05-18T14:19:26.780 回答
4
x => x.SomeBooleanProperty = true

这个 lambda 表示 - 对于 x,分配trueSomeBooleanProperty。赋值的结果也是值true

如果将其更改为:

x => x.SomeBooleanProperty

lambda 表示 - 对于 x 返回 的值SomeBooleanProperty

于 2012-05-18T14:20:19.490 回答
3

它编译是因为它是一个有效的Func<T, bool>. 在这种情况下,编译器无法告诉它,它不应该允许这样做。

于 2012-05-18T14:19:31.943 回答
0

看起来问题与以下事实有关

x => x.BooleanProperty = true

计算结果为真,因此是有效的 where() 谓词

我用整数尝试过,并且能够得到相同的行为。

[TestMethod]
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 这是意外的行为, IEnumerable<> 扩展应该都返回新的枚举并且不改变原来的,但我没有看到任何地方都能保证。

看起来它可以用作伪 foreach() 但我不推荐它:-/

艾伦。

于 2012-05-18T14:29:36.577 回答