说我有collection.Select(..).Where(...).Sum(...)
LINQ引擎会对集合执行1个或多个循环吗?
答案 0 :(得分:8)
Sum
会消耗过滤器Where
的输出,这会消耗投影Select
的输出,这将消耗collection
。 Sum
会将过滤后的序列移动一次,这会使投影走一次,这将导致collection
一次。因此,集合将重复一次。
这是一个可爱的实验,你可以做到这一点:
class Sequence : IEnumerable<int> {
public IEnumerator<int> GetEnumerator() {
for (int i = 0; i < 17; i++) {
Console.WriteLine(i);
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
然后:
Sequence sequence = new Sequence();
int sum = sequence.Select(x => 2 * x).Where(x => x % 4 == 0).Sum();
Console.WriteLine("Sum is {0}", sum);
输出将是:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum is 144
显示sequence
只迭代一次。
答案 1 :(得分:4)
这是一个类比(由于Jon Skeet),可以让你感受到这里发生的事情。
假设你有一个名为Collection的人有一副扑克牌。
“收集”旁边是“X X不是面卡”。
除了“Where”是“选择将卡值转换为整数”
“选择”旁边是“总和”。
你戳总和。 Sum进入循环。
总和选择。选择进入循环。
选择没有任何东西给Sum,所以选择戳到哪里。哪里进入循环。
pokes收集。收藏之手黑桃之王。
在哪里把它扔在地板上并再次捅收集。收藏之手那里的钻石女王,哪里扔在地板上。再次戳戳集合,这次集合手中的三心之心。
手中的三颗心选择。选择提取数字3并将其交给Sum。 Sum将其添加到零,然后返回到循环的顶部,并再次选择Select。
选择恢复循环,戳到哪里。在恢复循环的地方,反复戳戳Collection,直到Collection给出Where接受的地方。
所以它就是这样,将收集牌交给Where,在哪里扔掉它们或将它们传递给Select,并选择将数字输入Sum,这样可以保持一个总计。
当Collection最终说“没有”到Where,Where说“不再”选择时,Select会说“不再”为Sum,而Sum则返回给你的总和。
答案 2 :(得分:2)
这三个命令将有一个循环。
如果您想了解更多信息,我推荐Jon Skeet's blog,其中描述了LINQ to Objects的重新实现。