C#阻止收集被修改异常

C#阻止收集被修改异常,c#,collections,enumeration,C#,Collections,Enumeration,做 foreach(新列表中的T值(旧列表)) 当oldList包含一百万个对象T时是否危险(昂贵) 更一般地说,如果在枚举过程中可以添加/删除元素,那么在oldList上枚举的最佳方法是什么…我通常只为所有要删除或添加的对象创建一个列表 在foreach中,我只需将项目添加到适当的集合中,并在foreach完成后修改原始集合(通过removietems和addItems集合循环)一般规则是,您不应修改正在枚举的同一集合。如果要执行类似操作,请保留另一个集合,该集合将跟踪要从原始集合中添加/删

foreach(新列表中的T值(旧列表))
当oldList包含一百万个对象T时是否危险(昂贵)


更一般地说,如果在枚举过程中可以添加/删除元素,那么在oldList上枚举的最佳方法是什么…

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


foreach
中,我只需将项目添加到适当的集合中,并在
foreach
完成后修改原始集合(通过
removietems
addItems
集合循环)

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

这将是“缓慢的”,但您对此无能为力,除了在后台线程上运行它。例如,使用一个

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

如果使用多线程,则必须研究多线程编程,例如使用或可能更好的线程

更新:
正如在另一篇文章中提到的,现在在.NET 4.0中不需要任何努力就可以做到这一点。

您可以在不使用枚举器的情况下遍历列表,因此可以执行以下操作

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

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

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

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

   ...

   if(itemRemoveCondition) {
     oldList.RemoveAt(i--);
   }
}
var itemsToBeRemoved=new List();
foreach(myHugeList中的T项)
{
如果(/**/)
itemsToBeRemoved.添加(item);
}
myHugeList.Removate(itemsToBeRemoved);

对于我来说,首先你应该考虑使用某种数据分页,因为拥有这样一个百万分之一的大列表本身可能是危险的。

你听说过单位工作模式吗

您可以实现它,这样您就可以标记要创建、更新或删除的对象,稍后,您可以调用“SaveChanges”、“Commit”或任何其他执行“applychanges”的操作,您就可以完成了

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


无论如何,请避免列出数以百万计的项目。您应该使用分页的对象列表。

foreach(新列表中的T值(oldList).ToList())-尝试一下如果您使用foreach循环修改集合,则会出现如下错误

var itemsToBeRemoved = new List<T>();

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

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

    foreach (string s in li)
    {
        li.Remove(s);
    }
List li=新列表();
li.添加(“巴努”);
li.添加(“测试”);
foreach(以li表示的字符串s)
{
li.移除(s);
}
解决方案-用于循环,如下所示

var itemsToBeRemoved = new List<T>();

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

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

    foreach (string s in li)
    {
        li.Remove(s);
    }
for(int i=0;i
在枚举原始列表时,可以使用标志将修改切换到临时列表

///您正在枚举的位置

for (int i = 0; i < li.Count; i++)
    {
        li.RemoveAt(i);
        i--;
    }
isBeingEnumerated = true
foreach(T value in new List<T>(oldList) )
isBeingEnumerated = false
SyncList(oldList with temporaryList)

这里似乎有两个不同的问题。我不确定它们为什么被组合在一起。我发现这有点令人困惑;为什么不简单地在列表上向后循环?这样你就不需要混合递增和递减索引。如果你向后循环,你会遇到添加项的问题。循环的结束条件是否在每一次迭代还是一次迭代?结束条件将在每次迭代中被评估。真的,我错过了问题的补充部分。好吧,但实际上它是另一个可以修改集合的线程。由于某种原因,我不能同步迭代与添加/移除。正如我在更新的答案中提到的,如果您使用.NET 4,请考虑使用。并发收集。由于某些原因,我无法同步迭代与添加/删除。For迭代肯定是我问题的解决方案。我很乐意提供帮助。如果它是您问题的解决方案,请您将其标记为答案,单击“绿色复选标记”?:)谢谢!