2011-02-15 182 views
7

是否C#防止集合被修改例外

foreach(T value in new List<T>(oldList)) 

是危险的(昂贵的)时oldList包含1个百万物品T的?

更多generaly什么是枚举oldList因为元素可以添加/枚举过程中移除...

+0

好像有两个不同的问题在这里修改。我不确定他们为什么合并。 – 2011-02-15 10:29:26

回答

4

我通常只是创建一个列表被删除或添加的所有对象的最佳途径。

foreach我只是添加的项目,以适当的集合和修改原始集合后foreach已经完成(通过removeItemsaddItems收集循环)

7

一般的规则是,你不应该修改同您正在枚举的集合。如果你想做这样的事情,保留另一个集合,它将跟踪哪些元素添加/从原始集合中删除,然后在退出循环后,对原始集合执行添加/删除操作。

+0

好吧,但实际上它是另一个可以修改集合的线程。出于某种原因,我无法同步迭代与添加/删除。 – Toto 2011-02-15 10:34:27

+0

正如我更新的答案中所述,如果您使用的是.NET 4.0,请考虑使用“并发集合”。 – 2011-02-15 11:46:04

0

这将是'缓慢',但除了在后台线程上运行它外,您可以做的更多。例如。使用BackgroundWorker

如果您的列表操作仅发生在一个线程上,则正确的方法是将项目添加/删除到单独列表中,并在迭代完成后执行这些操作。

如果你使用多线程,你将不得不考虑多线程编程,使用locks或可能更好一个ReaderWriterLock

UPDATE: 作为另一个Stack Overflow question提到的,这是目前可能没有在.NET 4.0中when using concurrent collections任何努力。

0

你可以遍历列表,而不使用枚举,所以这样做......

for(int i = 0;i<oldList.Count;i++) { 
    var value = oldList[i]; 

    ... 

    if(itemRemoveCondition) { 
    oldList.RemoveAt(i--); 
    } 
} 
+1

我发现那种混乱;为什么不简单地在列表中向后循环?那么你不需要混合递增和递减索引。 – 2011-02-15 10:31:48

1

如果你的意思是你可以添加/从另一个线程删除对象,我想: 1同步线程 2-在添加/删除线程中,创建要添加或删除的项目列表 3-然后在关键部分中删除这些项目(因此它很小 - 在添加项目时不必同步到删除列表)

如果你不想这样做,你可以用它来代替fo达成,这将避免该异常,但你必须采取额外的照顾,让你没有得到其他类型的异常

4

就这样

var itemsToBeRemoved = new List<T>(); 

foreach (T item in myHugeList) 
{ 
    if(/*<condition>*/) 
     itemsToBeRemoved.Add(item); 
} 

myHugeList.RemoveRange(itemsToBeRemoved); 
0

对我来说的,第一件事情是你应该考虑使用一些这种类型的数据分页,因为拥有这样的1千万条目大的列表本身可能是危险的。

您是否听说过工作单元模式?

您可以实现它,以便标记创建,更新或删除对象,然后调用“SaveChanges”,“Commit”或任何其他执行“应用更改”的工作,您就完成了。

例如,您遍历枚举(oldList)并将它们标记为“delete”。之后,您调用“SaveChanges”,更抽象的通用工作单元将迭代小型,经过筛选的对象列表以供处理。

反正避免的畅想项的列表。您应该使用分页的对象列表。

-2

尝试用于词典。

int [] temp = Dictionary.Keys.ToArray();

  foreach (var c in temp) 
      { 
       if (condition) 
       { 
       //Your codes 
       } 

       else 
       { 

        Dictionary.Remove(c); 
        //OR 
        Dictionary.Add(c); 
       } 
0

的foreach(在新列表T中值(oldList).ToList()) - 给一个尝试

1

如果您使用的foreach循环修改集合,那么你会得到这个错误如下。

List<string> li = new List<string>(); 
    li.Add("bhanu"); 
    li.Add("test"); 

    foreach (string s in li) 
    { 
     li.Remove(s); 
    } 

解决方法 - 使用For循环如下。

for (int i = 0; i < li.Count; i++) 
    { 
     li.RemoveAt(i); 
     i--; 
    } 
0

您可以使用标志将修改切换到临时列表,而原始枚举。

///你在哪里枚举

isBeingEnumerated = true 
foreach(T value in new List<T>(oldList)) 
isBeingEnumerated = false 
SyncList(oldList with temporaryList) 

///你在哪里,而枚举

if isBeingEnumerated then 
use a temporaryList to make the changes.