C# 防止 Collection Was Modified 异常

发布于 2024-10-17 17:35:58 字数 183 浏览 4 评论 0原文

是否

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

当 oldList 包含 100 万个对象 T 时,

危险(成本高昂)?更一般地说,考虑到可以在枚举期间添加/删除元素,枚举 oldList 的最佳方法是什么...

Does

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

is dangerous (costly) when oldList contains 1 millions of object T ?

More generaly what is the best way to enumerate over oldList given that elements can be added/removed during the enumeration...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

虚拟世界 2024-10-24 17:35:58

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

The general rule is, you should not modify the same collection in which you are enumerating. If you want to do something like that, keep another collection which will keep track of which elements to add/remove from the original collection and then after exiting from the loop, perform the add/remove operation on the original collection.

一曲琵琶半遮面シ 2024-10-24 17:35:58

就像这样

var itemsToBeRemoved = new List<T>();

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

myHugeList.RemoveRange(itemsToBeRemoved);

just like this

var itemsToBeRemoved = new List<T>();

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

myHugeList.RemoveRange(itemsToBeRemoved);
心的憧憬 2024-10-24 17:35:58

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

foreach 中,我只需将项目添加到适当的集合中,并在 foreach 完成后修改原始集合(循环遍历 removeItems 和 <代码>addItems集合)

I usually just create a list for all the objects to be removed or added.

Within the foreach I just add the items to the appropriate collections and modify the original collection after the foreach have completed (loop through the removeItems and addItems collection)

时光匆匆的小流年 2024-10-24 17:35:58

您可以在不使用枚举器的情况下迭代列表,因此请执行以下操作...

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

   ...

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

You could iterate through the list without using an enumerator, so do something like...

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

   ...

   if(itemRemoveCondition) {
     oldList.RemoveAt(i--);
   }
}
苏别ゝ 2024-10-24 17:35:58

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

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

If you mean you can add/remove objects from another thread, I would:
1-synchronize the threads
2- in the add/remove threads, create a list of items to be added or deleted
3- and then delete these items in a critical section (so it is small - you don't have to synch while adding the items to the delete list)

If you dont want to do that, you can use for instead of foreach, that would avoid the exception, but you would have to take extra care so you do not get other kinds of exceptions

╄→承喏 2024-10-24 17:35:58

foreach(T value in new List(oldList).ToList() ) - 尝试一下

foreach(T value in new List(oldList).ToList() ) - give a try

累赘 2024-10-24 17:35:58

对我来说,第一件事是你应该考虑使用某种数据分页,因为拥有这样一百万个项目的大列表本身就可能很危险。

您听说过工作单元模式吗?

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

例如,您迭代可枚举 (oldList) 并将它们标记为“删除”。稍后,您调用“SaveChanges”,更抽象、更通用的工作单元将迭代要使用的小型、经过筛选的对象列表。

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

For me, first thing is you should consider using some kind of data paging, because having such 1-milion-items-large list could be dangerous itself.

Have you heard about Unit of Work pattern?

You can implement it so you mark objects for create, update or delete, and later, you call "SaveChanges", "Commit" or any other doing the job of "apply changes", and you'll get done.

For example, you iterate over the enumerable (oldList) and you mark them as "delete". Later, you call "SaveChanges" and the more abstract, generic unit of work will iterate over the small, filtered list of objects to work with.

Anyway, avoid lists of a milion items. You should work with paged lists of objects.

吹泡泡o 2024-10-24 17:35:58

它会很“慢”,但是除了在后台线程上运行它之外,您对此无能为力。例如,使用 BackgroundWorker

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

如果您使用多线程,则必须研究多线程编程,例如使用 锁定或者可能更好ReaderWriterLock

更新:
正如另一个 堆栈溢出问题,现在在 .NET 4.0 中无需任何努力即可实现此目的 使用并发集合时

It will be 'slow' but there is not much more you can do about it, except running it on a background thread. E.g. using a BackgroundWorker.

If your operations on the list only occur on one thread, the correct approach is to add the items to add/remove to seperate lists, and perform those operations after your iterations has finished.

If you use multiple threads you will have to look into multithreaded programming, and e.g. use locks or probably better a ReaderWriterLock.

UPDATE:
As mentioned in another Stack Overflow question, this is now possible without any effort in .NET 4.0 when using concurrent collections.

汹涌人海 2024-10-24 17:35:58

如果您使用 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--;
    }

If you are using Foreach loop for modifying collection then you will get this error as below.

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

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

Solution - use For Loop as below.

for (int i = 0; i < li.Count; i++)
    {
        li.RemoveAt(i);
        i--;
    }
人间不值得 2024-10-24 17:35:58

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

/// 枚举的位置

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.

you can use a flag to switch the modification to a temporary list while the original is being enumerated.

/// where you are enumerating

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

/// where you are modifying while enumerating

if isBeingEnumerated then
use a temporaryList to make the changes.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文