Linq Where local counter closure 在 VS watch 中产生不同的结果
Linq Where local counter closure different results in VS watch
我尝试使用 LinQ Where
扩展函数删除 array
中的前 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 }
结果 console.
但是在 watch 在 Visual Studio 2015 更新 3 在 test2
和 test3
的情况下我有错误的结果:
谁能解释为什么我使用 .ToList()
和 .ToArray()
时一切正常,而在其他情况下却出错?
这是错误吗?
不同之处在于延迟执行具有副作用的 lambda。在这里你必须非常小心,因为每次 Where
产生的 IEnumerable<T>
被枚举时都会计算 lambda,导致它的副作用(即递增 deletedTestX
)一次又一次。
当您 运行 程序时,您的四个序列中的每一个都被恰好枚举一次。对于情况 1 和 4,枚举发生在 ToList
和 ToArray
内,而对于情况 2 和 3,它发生在 string.Join
.
内
当您在调试器中打开结果时,手表的控制器 window 必须 运行 您的枚举才能显示结果。这是您的序列的第二个枚举,因此它发生在已经应用第一个枚举的副作用的情况下。这就是您在调试 window.
中看到错误索引的原因
您可以通过将每个结果打印两次来在您的程序中重现此行为:
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)}}}");
我尝试使用 LinQ Where
扩展函数删除 array
中的前 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 }
结果 console.
但是在 watch 在 Visual Studio 2015 更新 3 在 test2
和 test3
的情况下我有错误的结果:
谁能解释为什么我使用 .ToList()
和 .ToArray()
时一切正常,而在其他情况下却出错?
这是错误吗?
不同之处在于延迟执行具有副作用的 lambda。在这里你必须非常小心,因为每次 Where
产生的 IEnumerable<T>
被枚举时都会计算 lambda,导致它的副作用(即递增 deletedTestX
)一次又一次。
当您 运行 程序时,您的四个序列中的每一个都被恰好枚举一次。对于情况 1 和 4,枚举发生在 ToList
和 ToArray
内,而对于情况 2 和 3,它发生在 string.Join
.
当您在调试器中打开结果时,手表的控制器 window 必须 运行 您的枚举才能显示结果。这是您的序列的第二个枚举,因此它发生在已经应用第一个枚举的副作用的情况下。这就是您在调试 window.
中看到错误索引的原因您可以通过将每个结果打印两次来在您的程序中重现此行为:
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)}}}");