4

我嘗試刪除array中的前3個元素與LinQ Where擴展功能。Linq本地計數器關閉不同的結果VS手錶

下面是一個例子:

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 }結果控制檯

但在在Visual Studio 2015年更新3 test2test3情況下,我有錯誤的結果:

enter image description here

任何人都可以解釋爲什麼一切都很好,當我在其他情況下使用.ToList().ToArray()與錯?

這是錯誤嗎?

+4

隨着'ToList()'和'ToArray的()'你的數據物化到一個列表/陣列。其他人都是'IEnumerable',它們有效地承諾運行數據,並且在'Console.WriteLine'中運行它們兩次,一次在調試器中查看它們。沒有錯誤。 – DavidG

回答

2

不同之處在於延期執行帶有副作用的lambda。這裏必須非常小心,因爲每次Where生成的IEnumerable<T>被枚舉時,都會評估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.