【问题标题】:Why is this LINQ query not executed when using foreach?为什么使用 foreach 时不执行此 LINQ 查询?
【发布时间】:2013-09-25 20:43:47
【问题描述】:

在 LINQ 语句中创建新对象时,例如:

var list = new List<string>() { "a", "b", "c" };
var created = from i in list select new A();

A 类看起来像这样:

class A
{
    public string Label;
}

然后用 foreach 循环修改 A 中的属性:

foreach (var c in created) {
    c.Label = "Set";
}

为什么之后访问IEnumerable中的对象时没有设置值。例如。以下断言失败:

Assert.AreEqual("Set", created.ElementAt(2).Label);

我想知道为什么会这样。我希望 foreach 语句执行查询,并触发对象的创建。 MSDN 文档指出:"Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop"

我已经用 .NET 4.5 和 Mono 3.2.0 重现了这种行为。在访问创建的对象之前在IEnumerable 上调用ToList 可以解决此问题。

【问题讨论】:

  • 它与“未执行”相反——它被执行了两次——当它第二次执行时,一个newA s 已创建。
  • 因为created 是查询而不是集合。每次访问它时,您都会再次执行它。因此,如果您在foreach 之后再次枚举查询,您将获得一组全新的IEnumerable&lt;A&gt;。这就是延迟执行的本质。如果您要查询A 的现有集合,您将更改现有的持久对象。

标签: c# .net linq foreach deferred-execution


【解决方案1】:

这是因为created 是一个查询,而不是一个结果。因此,每次枚举它时,您都是在从头开始重新评估 Select

如果您希望它起作用,请将 created 设为实际列表,而不仅仅是表示查询的 IEnumerable

例如,添加:

created = created.ToList();

你说:

我希望 foreach 语句执行查询,并触发对象的创建

这正是正在发生的事情。问题是每次迭代created 时都会创建对象,而不仅仅是第一次。由于ElementAt() 方法迭代created,它只是再次创建新的As。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多