2014-04-30 55 views
2

我知道,在列舉枚舉時更改集合將導致collection was modified exception。 但是,如果我從較大的子集合中獲得子集合,並且在枚舉子集合時,我從較大的子集中刪除某個項目,但仍然會出現此錯誤。在子集合上調用ToList可解決此問題。但爲什麼會發生?集合在枚舉新子集合時被修改異常

var localCollection = someData.ToList(); // from DB Context 
var localGrouped = localCollection.GroupBy(x => x.Id).Select(g => new { Id = g.Key, List = g.Select(x => x.Value) }); or .ToList(); // Here how I solve exception 

var groups = new List<List<Int64>>(); 

while (localGrouped.Any()) 
{ 
    var newSelected = new List<Int64>(); 

    var firstGroup = localGrouped.First(); 
    newSelected.Add(firstGroup.Id); 

    localGrouped.Remove(firstGroup); 

    var similiarGroups = localGrouped.Where(x => x.List.Intersect(firstGroup.List).Any()).ToList(); 
    if (similiarGroups.Any()) 
    { 
     foreach (var similiarGroup in similiarGroups) 
     { 
     //Changing something here in parent collection causes exception 
      newSelected.Add(similiarGroup.Id); 
      localGrouped.Remove(similiarGroup); 
     } 
    } 
    groupsOfParcels.Add(newSelected); 
} 
+0

您仍在枚舉子集合中的外部集合。 – Shoe

+0

不是@Shoe。外部循環是'while(localGrouped.Any())',它會在每次迭代開始時迭代localGrouped,但不會迭代* over。 – jwg

回答

6

Where不是子集合,它是一個過濾器。區別在於LINQ的工作原理。

您可以認爲Where大致上是保存了對原始IEnumerable的引用,以及一些檢查條件的代碼和一些說明它已經走了多遠的狀態。當您在Where的輸出上執行getNext()時,代碼段會經過原始IEnumerable,直到找到滿足條件的元素,然後返回它(或到達原始IEnumerable的末尾,這意味着它也位於結尾Where)。

這是懶惰評估 - 它只在任何時候看它所需的條款。所以原始的IEnumerable必須在整個過程中一直存在並且未被修改。如果您致電ToList(),評估將立即進行 - 在繼續之前,所有元素將被提取並放入列表中。

最好的東西來讀這個是由C#和Linq神Jon Skeet。他的文章包括所有主要Linq函數的重新實現,並詳細討論實現問題,以便您可以確切地瞭解他們(可能)的工作方式。

Introduction

Part 2 - Where(!)

+1

「林克神Jon Skeet」赫赫,upvoted。 –

+0

不會ToList()方法產生一個新的列表? – MaxOvrdrv

+0

我不確定你的問題是@MaxOvrdrv? – jwg

4

GroupByWhereSelect,和大多數其他LINQ操作簡單地從底層集合抓住IEnumerable並遍歷它。底層IEnumerable在嘗試獲取下一個項目時引發異常,因爲該集合已被修改。這個異常是通過每個LINQ操作員拋出的,因爲如果它不能從底層序列中獲取下一個項目,它就無法完成它的工作。

使用ToList你強迫整個序列進行枚舉你已經修改了收集之前,而不是讓底層列表的枚舉推遲到之後該名單已被修改。

+0

任何想到這個http://stackoverflow.com/questions/36215695/not-able-to-dispose-datatable-in-foreach-loop? – Neel

+0

@CoreDeveloper你在迭代它時正在修改一個集合。 – Servy

+0

但我已經使用.ToList如答案中所示。它仍然可能出現任何機會? – Neel

相關問題