C# 为什么在使用foreach时不执行此LINQ查询?

C# 为什么在使用foreach时不执行此LINQ查询?,c#,.net,linq,foreach,deferred-execution,C#,.net,Linq,Foreach,Deferred Execution,在LINQ语句中创建新对象时,例如: var list = new List<string>() { "a", "b", "c" }; var created = from i in list select new A(); 然后使用foreach循环修改中的属性: foreach (var c in created) { c.Label = "Set"; } 为什么在以后访问IEnumerable中的对象时不设置这些值。例如,以下断言失败: Assert.AreEqua

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

var list = new List<string>() { "a", "b", "c" };
var created = from i in list select new A();
然后使用foreach循环修改中的属性:

foreach (var c in created) {
    c.Label = "Set";
}
为什么在以后访问
IEnumerable
中的对象时不设置这些值。例如,以下断言失败:

Assert.AreEqual("Set", created.ElementAt(2).Label);
我想知道为什么会这样。我希望foreach语句执行查询,并触发对象的创建。MSDN文档状态:


我用.NET4.5和Mono3.2.0复制了这种行为。在访问创建的对象之前调用
IEnumerable
上的
ToList
,可以解决此问题。

之所以发生此问题,是因为创建的
是一个查询,而不是结果。因此,每次枚举它时,您都要从头开始重新计算
Select

如果您希望这样做,请将
created
设置为实际列表,而不仅仅是表示查询的
IEnumerable

例如,添加:

created = created.ToList();
你说:

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


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

它与“not executed”(未执行)相反,执行两次,第二次执行时,会创建一组新的
A
。因为
created
是一个查询,而不是一个集合。每次访问它时,都会再次执行它。因此,如果在
foreach
之后再次枚举查询,您将得到一组新的
IEnumerable
。这就是延期执行的本质。如果您要查询一个现有的
A
集合,您需要更改现有的持久对象。
created = created.ToList();