C# 如何从ObservableCollection中删除项?

C# 如何从ObservableCollection中删除项?,c#,foreach,ienumerable,observablecollection,enumerator,C#,Foreach,Ienumerable,Observablecollection,Enumerator,可能重复: 假设我有一个ObservableCollection mycollection,我想通过枚举器做一些事情,比如: foreach(var x in mycollection) { // This will do something based on data of x and remove x from mycollection x.Close(); } 方法Close()有一行代码-mycollection.Remove(x)。运行此代码时,出现以下错误: 收集被修

可能重复:

假设我有一个
ObservableCollection mycollection
,我想通过枚举器做一些事情,比如:

foreach(var x in mycollection)
{
   // This will do something based on data of x and remove x from mycollection
   x.Close();
}
方法
Close()
有一行代码-
mycollection.Remove(x)。运行此代码时,出现以下错误:

收集被修改;枚举操作不能执行


我无法更改方法
Close()
,因为它在应用程序的许多其他位置都被调用。如何解决此问题?

在foreach中,使用mycollection.ToList()
代替。

有两种方法可以解决此问题:

  • 如果不需要从列表中删除所有内容,请使用
    foreach
    填充单独的“要关闭的项目”列表,并在完成后为第二个列表中的每个项目调用
    .Close
    。这样,您可以避免在枚举时修改
    mycollection
  • 如果要对列表中的每个项目调用
    Close
    ,请尝试以下操作:

    while (mycollection.Count > 0
    { 
         mycollection[0].Close()) 
    }
    

  • 枚举集合时无法删除项。 一个简单的解决方案是使用
    for
    循环从最后一项转到第一项,并根据需要删除:

    for (int i = myCollection.Count - 1; i >= 0; i--)
    {
        var item = myCollection[i];
        if (ShouldDelete(item))
        {
            item.Close();
        }
    }
    

    我不熟悉ToList()方法,但它可以做两件事之一:首先,它可以将集合强制转换为列表并返回它,在这种情况下,您将得到与原始代码相同的异常。或者,它可以将集合复制到一个全新的列表中,在这种情况下,您在循环的每个迭代中复制整个集合,这是非常低效的。不管怎样,这都不是一个好答案。@Chris,这是不对的。这将复制列表一次,而不是每次迭代。这是解决无效枚举数问题的一种非常有效且简单的方法,并且非常常用。如果需要特殊的优化,那么使用for循环肯定会更有效。然而,仅仅是使用了一个
    ObservableCollection
    这一事实告诉我,这里的情况可能不是这样。顺便说一句,我很想将Close()方法更改为不负责从集合中删除该项。这段代码可能会让人非常困惑,因为它使这个循环看起来像一个无限循环-集合是否正在被修改并不明显(你必须知道关闭的内部细节),这使得循环条件看起来要么总是正确的,要么总是错误的。@Chris:同意,尽管在某些情况下这可能是有意义的(例如,关闭连接会将其从连接池中移除的连接池)。不过,构建此代码肯定有更优雅的方法。