2016-02-25 31 views
0

我最初設置我的參數類型爲ICollection,因爲我認爲我會遇到IEnumerable的多個枚舉問題。但是,Resharper建議我可以將參數類型轉換爲IEnumerable。最後我做一個測試,以雙重檢查,似乎很好地工作:這不會導致IEnumerable的多次枚舉?

private static void Main(string[] args) 
    { 
     var nums = GetNums(); 
     MultipleEnumerations(nums); 
     Console.ReadLine(); 
    } 

    private static void MultipleEnumerations(IEnumerable<int> nums) 
    { 
     var otherNums = new List<int> {1, 2, 3, 4, 5}; 
     var filtered = otherNums.Where(num => nums.Contains(num)); 
     foreach (var num in filtered) 
     { 
      Console.WriteLine(num); 
     } 
    } 

    private static IEnumerable<int> GetNums() 
    { 
     yield return 4; 
     yield return 2; 
    } 

這怎麼不會導致IEnumerable的多個枚舉?

+0

'otherNums'是一個列表。 – Brandon

+0

你能解釋爲什麼你認爲它會導致多個枚舉? - 試用後,你是對的:沒有實現數組,你將要做多個枚舉。也許這只是R#無法很好檢測的場景。 –

+0

爲了確定otherNums列表中的數字是否在nums IEnumerable中,它必須迭代nums中的所有元素。既然我們正在檢查otherNums中的每個int,我會認爲這將是多個枚舉。 – tmajest

回答

0

Resharper可能建議將參數的類型更改爲IEnumerable,因爲沒有調用者可以通過IEnumerable以外的其他類型,Resharper建議使用最簡單的類型。

ICollection只爲IEnumerable添加了一些屬性和方法,最重要的是它屬於Count屬性。

根據this table,對於實現ICollection的大多數類,GetEnumerator()方法具有相同的複雜度。

2

這確實導致多個枚舉可枚舉。

如果我改變你的代碼如下:

private static void MultipleEnumerations(IEnumerable<int> nums) 
{ 
    var otherNums = new List<int> { 1, 2, 3, 4, 5 }; 
    var filtered = otherNums.Where(num => 
    { 
     Console.WriteLine("{0}?", num); 
     return nums.Contains(num); 
    }); 
    foreach (var num in filtered) 
    { 
     Console.WriteLine(num); 
    } 
} 

private static IEnumerable<int> GetNums() 
{ 
    Console.WriteLine("4!"); 
    yield return 4; 
    Console.WriteLine("2!"); 
    yield return 2; 
} 

...然後我可以得到以下的輸出:

 
1? 
4! 
2! 
2? 
4! 
2! 
2 
3? 
4! 
2! 
4? 
4! 
4 
5? 
4! 
2! 

你可以看到,對於正在測試的每個otherNums它是通過運行nums(它是GetNums)。在測試4時,它只需要第一個數字nums,否則它將完全迭代5次。

如果你想知道爲什麼.Whereforeach不重複通的otherNums這是因爲.Where與延遲執行模式運行 - 它當你做一個foreach或類似的東西.ToList(),它執行的唯一。