对于那些比我更了解.Net内部运作方式的人来说,这只是一个简单的问题:: - )。我只是觉得我明白了什么。
我看到它的方式,当你在foreach中运行LINQ时,LINQ枚举器被评估(运行),它返回一个集合,foreach继续在该集合上运行。但是......我仍然不确定:
foreach (VCCTreeItem ti in (from treeItems in TreeItems select treeItems))
在每个循环中是否重新评估(执行)LINQ语句?我会想(并希望)不。但是,在使用foreach
中的集合执行操作时,如果修改了集合,则会在运行时收到错误消息。这让我相信在幕后可能会发生一些可疑的事情。我从来没有时间详细拆解/检查这个,所以这就是我问你的原因。我相信你们中的一些人从头顶知道了答案:: - D。
哦,我想我可以问同样的问题:
foreach (VCCTreeItem ti in TreeItems)
如果TreeItems是get
我执行某些操作的属性,则将对该属性进行求值,作为值返回,并且foreach将对该值进行操作。
答案 0 :(得分:6)
IEnumerable
未重新评估。这样的foreach
语句:
IEnumerable<Foo> enumerable = ...;
foreach (Foo f in enumerable) {
...
}
对应于此(编辑:enumerator
也放在using
块中,如@Double Down所示:
IEnumerable<Foo> enumerable = ...;
IEnumerator<Foo> enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext()) {
Foo f = enumerator.Current;
...
}
因此,如果您有一些代价高昂的操作会产生您正在循环的集合,那么这不是问题;它只会生产一次。但是在LINQ中,正如@Double Down所说,大多数结果都是懒散产生的 - 因此对GetEnumerator()
的调用几乎没有任何作用,而每次调用MoveNext()
时结果都会逐渐产生。总的来说,这与在一个操作中生成整个列表一样耗时,但它节省了内存(从不生成包含所有元素的实际List
;您一次获得一个元素,然后丢弃它)。 / p>
答案 1 :(得分:3)
Linq正在进行后期绑定评估(使用yield关键字)。当你在IEnumerator中调用MoveNext()时,它仅被评估下一个项目,它不会在每次下一次调用时从头开始重新计算。
如您所知,您的foreach循环评估为
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
{
// Loop body.
}
}