对于LINQ Select中的每个

时间:2011-02-25 19:54:50

标签: c# linq

对于那些比我更了解.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将对该值进行操作。

2 个答案:

答案 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.
    }
}