C#阻止Collection被修改的异常

时间:2011-02-15 10:17:07

标签: c# collections enumeration

 foreach(T value in new List<T>(oldList) )
当oldList包含1百万个对象T时,

是危险的(代价高昂)?

更常见的是,在枚举期间添加/删除元素时,枚举oldList的最佳方法是什么...

10 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:4)

我通常只为要删除或添加的所有对象创建一个列表。

foreach中,我只是将项目添加到相应的集合中,并在foreach完成后修改原始集合(循环遍历removeItemsaddItems集合)

答案 2 :(得分:4)

就像这样

var itemsToBeRemoved = new List<T>();

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

myHugeList.RemoveRange(itemsToBeRemoved);

答案 3 :(得分:1)

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

如果您不想这样做,您可以使用for而不是foreach,这样可以避免异常,但您必须格外小心,以免出现其他类型的异常

答案 4 :(得分:1)

如果您使用Foreach循环来修改集合,那么您将收到如下错误。

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

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

解决方案 - 使用For Loop,如下所示。

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

答案 5 :(得分:0)

它会“慢”但除了在后台线程上运行之外,你无法做更多的事情。例如。使用BackgroundWorker

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

如果使用多个线程,则必须研究多线程编程,例如:使用locks或更好的ReaderWriterLock

更新: 正如另一个Stack Overflow question中所提到的,现在可以在.NET 4.0 when using concurrent collections中毫不费力地实现。

答案 6 :(得分:0)

您可以在不使用枚举器的情况下遍历列表,所以请执行类似......

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

   ...

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

答案 7 :(得分:0)

对我而言,首先应该考虑使用某种数据分页,因为拥有这样的1百万项大型列表本身就很危险。

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

您可以实现它,以便标记对象以进行创建,更新或删除,之后,您可以调用“SaveChanges”,“Commit”或其他任何“应用更改”的工作,您将完成。< / p>

例如,您遍历可枚举(oldList)并将其标记为“delete”。稍后,您调用“SaveChanges”,更抽象,通用的工作单元将遍历要处理的小的,已过滤的对象列表。

无论如何,请避免使用百万件物品。您应该使用分页的对象列表。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

///您要枚举的地方

lintOptions {
    disable 'MissingTranslation'
}

///在枚举时修改的位置

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