这个问题在这里已经有答案了:

复制

在迭代集合时修改集合


有没有人有一个很好的模式,可以让我在循环遍历可枚举集合(例如,字典中的 IList 或 KeyValuePairs)时解决无法删除对象的问题

例如,以下内容会失败,因为它修改了 foreach 期间枚举的列表

foreach (MyObject myObject in MyListOfMyObjects)
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

过去我用过两种方法。

我已将 foreach 替换为反向 for 循环(以便在删除对象时不会更改正在循环的任何索引)。

我还尝试存储要在循环中删除的新对象集合,然后循环遍历该集合并从原始集合中删除对象。

这些工作正常,但都不是 感觉 很好,我想知道是否有人想出了更多 优雅的 问题的解决方案

有帮助吗?

解决方案

有一个有用的 List<T>.RemoveAll(Predicate<T> match) 我认为是为此设计的方法: http://msdn.microsoft.com/en-us/library/wdka673a.aspx

其他提示

这有点简单,但是当我计划从 IEnumerable/IList 中删除项目时,我通常只制作一个副本:

foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

这不是最有效的方法,但很容易阅读。过早的优化等等。

执行相反的操作,创建一个新列表:

List myFilteredList = new List();
foreach (MyObject myObject in myListOfMyObjects)
{
     if (!condition) myFilteredList.Add(myObject);
}

然后在任何需要的地方使用新列表。

您还可以轻松地使用 LINQ 表达式,再次反转条件。这具有不创建新结构的额外好处,但也有它是惰性可枚举的缺陷:

var myFilteredList = from myObject in myListOfMyObjects
                     where !condition
                     select myObject;

但是,如果您确实需要从列表中删除项目,我通常使用“创建新列表,然后重申并删除”方法。

我刚刚看到这篇文章并认为我会分享。

void RemoveAll(object condition)  
{

    bool found = false;

    foreach(object thisObject in objects)    
    {

        if (condition)    
        {    
            objects.Remove(thisObject);

            found = true;

            break; //exit loop    
        }     
     }

    // Call again recursively

    if (found) RemoveAll(condition);

}

我不喜欢反向 for 循环的想法,因为它只适用于某些数据结构。

一般来说,我会使用第二种技术并将要删除的项目累积在单独的“待删除”集合中。如果删除可能导致现有迭代无效(例如,任何平衡树集合都会发生这种情况),那么我没有找到解决此问题的方法。

我偶尔使用的唯一其他技术是当您找到第一个要删除的元素时重新启动整个迭代。如果您没有找到任何要删除的项目,那么该功能就完成了。这是低效的,但有时是必要的,如果从集合中删除一个项目可能会更改需要删除的一组项目。

我有一本字典,想要处理所有值。当每个值被处理时,它会将自身从字典中删除,这会产生您讨论的问题。我做了以下事情:

foreach (var o in dictionary.Values.ToList())
{
  o.Dispose();
}

我很高兴这可能已经死了,但我总是这样做的方式是:

foreach(MyListOfMyObjects 中的 MyObject myObject)
{

if (条件) MyListOfMyObjects.Remove(myObject);

休息;

}

对象被删除,然后循环退出,中提琴!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top