C# 对于LINQ中的每一个,选择

C# 对于LINQ中的每一个,选择,c#,linq,C#,Linq,对于那些比我更了解.Net内部工作原理的人来说,这只是一个简单的问题::-)。我只是想确定我明白一些事情 在我看来,当您在foreach中运行LINQ时,将对LINQ枚举数求值(run),它返回一个集合,foreach将继续处理该集合。但是不过,我不确定: foreach (VCCTreeItem ti in (from treeItems in TreeItems select treeItems)) 是否在每个循环中重新计算(执行)LINQ语句?我认为(并希望)不会。但是,当在foreac

对于那些比我更了解.Net内部工作原理的人来说,这只是一个简单的问题::-)。我只是想确定我明白一些事情

在我看来,当您在foreach中运行LINQ时,将对LINQ枚举数求值(run),它返回一个集合,foreach将继续处理该集合。但是不过,我不确定:

foreach (VCCTreeItem ti in (from treeItems in TreeItems select treeItems))
是否在每个循环中重新计算(执行)LINQ语句?我认为(并希望)不会。但是,当在
foreach
中对集合执行操作时,如果集合被修改,则会在运行时收到错误消息。这让我相信幕后可能发生了一些可疑的事情。我从来没有时间详细地拆卸/检查这个,所以这就是我问你这个问题的原因。我相信你们中的一些人从他们的头脑中知道答案::-D

哦,我想我可以问同样的问题:

foreach (VCCTreeItem ti in TreeItems)

如果TreeItems是一个属性,我在它的
get
中执行一些操作,则该属性将被求值并作为值返回,foreach将对该值进行操作。

不会重新求值
IEnumerable
。类似这样的
foreach
语句:

IEnumerable<Foo> enumerable = ...;
foreach (Foo f in enumerable) {
    ...
}

因此,如果您有一些成本高昂的操作来生成正在循环的集合,这不是问题;它只生产一次。不过,在LINQ中,正如@Double Down所说,大多数结果都是延迟生成的,因此对
GetEnumerator()
的调用几乎什么也不做,而对
MoveNext()的每次调用都会增量生成结果。总的来说,这与在一次操作中生成整个列表一样耗时,但它节省了内存(包含所有元素的实际
列表
永远不会生成;您一次获得一个元素,然后丢弃它)。

Linq正在进行后期绑定评估(使用yield关键字)。在IEnumerator中调用MoveNext()时,只对下一项求值,而不会在每次move next调用中从头开始重新计算

如您所知,foreach循环的计算结果为

using (var enumerator = enumerable.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        // Loop body.
    }
}

谢谢你帮我睡得更好::-D.没问题。顺便说一下,一个有趣的学习练习是自己实现一对
IEnumerable
IEnumerator
类。例如,您可以创建一个类,其构造函数接受两个整数
a
b
,当它被枚举时,它会生成
a
b
之间的所有整数。除了进一步了解如何使用这些接口外,您还可以在类的实例上使用
foreach
,亲自查看
GetEnumerator()
只调用一次。:-)这是一个好主意::-D.但是当你站在我的立场上,试图建立一个巨大的项目,实现你的梦想,同时又靠独立的预算生活,而你所做的大部分事情都是免费和开源的,生活往往会提醒你时间是宝贵的。因此,我将接受您的答案,无需进一步验证::-)。我不是懒惰,我只是时间紧迫。我知道,每个人都是。但我也做了一些开源的东西。。。此外,我的其他项目目前也赚不了多少钱(阅读0)。唉,我不知道为什么我刚刚进行了这趟论证之旅,LOLI明白了-祝你的项目好运,并时刻关注在生产代码中实现
IEnumerable
的机会;-)
using (var enumerator = enumerable.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        // Loop body.
    }
}