Linq哪里有本地计数器关闭不同结果VS手表

时间:2017-08-12 18:06:48

标签: c# linq visual-studio-2015 closures visual-studio-debugging

我尝试使用LinQ array扩展功能删除Where中的前3个元素。

以下是一个例子:

var array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var count = 3;
var deletedTest1 = 0;
var test1 = array.Where(x => ++deletedTest1 > count).ToList();
Console.WriteLine($"{{{String.Join(", ", test1)}}}");
var deletedTest2 = 0;
var test2 = array.Where(x => ++deletedTest2 > count).AsEnumerable();
Console.WriteLine($"{{{String.Join(", ", test2)}}}");
var deletedTest3 = 0;
var test3 = array.Where(x => ++deletedTest3 > count);
Console.WriteLine($"{{{String.Join(", ", test3)}}}");
var deletedTest4 = 0;
var test4 = array.Where(x => ++deletedTest4 > count).ToArray();
Console.WriteLine($"{{{String.Join(", ", test4)}}}");

效果很好,在每种情况下我都会{ 4, 5, 6, 7, 8, 9 }导致控制台

但在test2test3中的Visual Studio 2015 Update 3中的中,我的结果有误:

enter image description here

当我在其他情况下使用.ToList().ToArray()以及错误时,有人可以解释为什么一切正常吗?

那是错误吗?

1 个答案:

答案 0 :(得分:2)

差异是由于延迟执行带副作用的lambda。这里你必须非常小心,因为每次IEnumerable<T>产生的Where被枚举时都会评估lambda,从而导致其副作用(即递增deletedTestX)。

运行程序时,您的四个序列中的每一个都只列举一次。对于案例1和案例4,枚举发生在ToListToArray内,而案例2和3则发生在string.Join内。

在调试器中打开结果时,监视窗口的控制器必须运行枚举才能显示结果。这是序列的第二个枚举,因此它已经应用了第一个枚举的副作用。这就是你在调试窗口中看到错误索引的原因。

您可以通过两次打印每个结果在程序中重现此行为:

var array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var count = 3;
var deletedTest1 = 0;
var test1 = array.Where(x => ++deletedTest1 > count).ToList();
Console.WriteLine("Test 1, deletedTest1={0}", deletedTest1);
Console.WriteLine($"{{{String.Join(", ", test1)}}}");
Console.WriteLine("Test 1, deletedTest1={0}", deletedTest1);
Console.WriteLine($"{{{String.Join(", ", test1)}}}");
var deletedTest2 = 0;
var test2 = array.Where(x => ++deletedTest2 > count).AsEnumerable();
Console.WriteLine("Test 2, deletedTest2={0}", deletedTest2);
Console.WriteLine($"{{{String.Join(", ", test2)}}}");
Console.WriteLine("Test 2, deletedTest2={0}", deletedTest2);
Console.WriteLine($"{{{String.Join(", ", test2)}}}");
var deletedTest3 = 0;
var test3 = array.Where(x => ++deletedTest3 > count);
Console.WriteLine("Test 3, deletedTest3={0}", deletedTest3);
Console.WriteLine($"{{{String.Join(", ", test3)}}}");
Console.WriteLine("Test 3, deletedTest3={0}", deletedTest3);
Console.WriteLine($"{{{String.Join(", ", test3)}}}");
var deletedTest4 = 0;
var test4 = array.Where(x => ++deletedTest4 > count).ToArray();
Console.WriteLine("Test 4, deletedTest4={0}", deletedTest4);
Console.WriteLine($"{{{String.Join(", ", test4)}}}");
Console.WriteLine("Test 4, deletedTest4={0}", deletedTest4);
Console.WriteLine($"{{{String.Join(", ", test4)}}}");

Demo.