考虑以下代码。
namespace ConsoleApp1
{
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main(string[] args)
{
int count = default(int);
IEnumerable<int> values1 = Enumerable.Range(1, 200)
.OrderBy(o => Guid.NewGuid())
.Take(100);
IEnumerable<int> values2 = values1
.OrderBy(o => Guid.NewGuid())
.Take(50)
.Select(o => { count++; return o; });
Console.Read();
}
}
}
复现步骤
- 在
Console.Read();
上设置断点 - 运行到断点处
- 检查
count++
(应该显示为0) - 检查
values2
并填充“结果视图” - 检查
count++
(应该显示为100)
问题
考虑到我只从 values1
中取了50个项目,我期望 count++
显示50。为什么它显示100?
请注意,如果这很困惑,请尝试运行此代码,因为它会产生相同的结果...
namespace ConsoleApp1
{
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main(string[] args)
{
int count = default(int);
IEnumerable<int> values1 = Enumerable.Range(1, 100)
.OrderBy(o => Guid.NewGuid())
.Take(50);
IEnumerable<int> values2 = values1
.OrderBy(o => Guid.NewGuid())
.Take(50)
.Select(o => { count++; return o; });
Console.Read();
}
}
}
示例
检查count ++
检查values2
(填充结果视图)
检查count ++
请解释这里正在发生什么,并说明如何修复它。
注意
许多给出的答案都暗示了延迟执行。我知道linq使用延迟执行,所以除非我错过了什么,否则这不是问题。
我的观点是,当断点被击中时,CLR已经为values2创建了一个状态机。然后在调试器中对其进行迭代,count立即增加到100,这似乎只有1次迭代。这似乎有点奇怪!
此外,我知道value2的结果视图的后续填充会导致count递增,因为这会导致状态机进一步迭代。
foreach
之后输出它,您将得到预期的 50:foreach (int i in values2); Console.WriteLine(count);
- Tim Schmelter