考虑以下代码
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)问题
鉴于我只从中取出了50个项目values1
,因此我希望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创建了一个状态机。然后在调试器中对其进行迭代,对于似乎只有1次迭代的计数立即增加到100。这似乎有点奇怪!
另外,我知道value2的结果视图的后续填充会导致计数增加,因为这会导致状态机的进一步迭代。
每次检查时values2
,都会重新评估该表达式-如果您在监视窗口中对其进行检查,它似乎每次都会被评估两次(不要问我为什么;请问编写监视窗口代码的人)。我知道了count == 300
。每当某计算它,把它添加50
到count
; 这就是代码的作用,请自己看看。并且,每次在监视窗口中将其扩展时,它都会count
增加100。因此,监视窗口对其进行两次评估。
您只看到其中一次,那又如何呢?VS代码中包含许多内容,因此不会显示给您。GUI不是进入程序内部的窗口;它不是程序内部的窗口。它是屏幕上的一堆像素,有些代码是故意着色的。我可以编写一个观察窗口,对表达式进行19次评估,并向您显示Pokemon。更合理的解释是:您从未见过的某些代码正在执行某种可能不会在GUI中显示的操作,或者有时您的计算机无法添加?
看看运行时类型values2
:System.Linq.Enumerable.WhereSelectEnumerableIterator<int, int>
。那不是集合,那是等待执行的东西。
让我们添加ToList()
到该表达式的末尾。它将对其进行一次评估并存储结果。然后,您可以整天检查结果,而无需再次执行任何LINQ表达式。
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; })
.ToList();
现在count == 50
,由于该表达式只计算一次,结果存储在中List<T>
。
屏幕上的点是一种错觉,将懒惰的评估与副作用结合起来,就像用机枪将猴子放到星巴克中一样。我并不是说这是错误的,并不是所有人都认为有一个有趣的约会。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句