在迭代期间从SortedList中删除是否安全

时间:2010-04-23 12:35:11

标签: c# .net ienumerator

我的问题是枚举器从SortedList中删除项目是否安全?

SortedList<decimal, string> myDictionary;
// omitted code

IEnumerator<decimal, string> enum = myDictionary.GetEnumerator();

while(enum.MoveNext)
{
  // is it ok to remove here?
  myDictionary.Remove(enum.Current.Key);
}

6 个答案:

答案 0 :(得分:8)

这将抛出异常 - 您无法在迭代时修改集合。

如果你仔细想一想,你会理解为什么。如果允许在集合中添加或删除,则不再迭代同一集合 - 您要么太多(添加),要么没有足够的项目(删除)。

答案 1 :(得分:4)

如前所述,你不想做什么。但是,另一种解决方案是简单地维护标记为删除的项目列表,然后删除这些后续词。我也会选择foreach而不是while循环,例如。

var removeList = new List<decimal>();
foreach (var item in myDictionary)
{
    // have a condition which indicates which items are to be removed
    if (item.Key > 1)
    {
        removeList.Add(item.Key);
    }
}

或者,如果您只是尝试检索要删除的项目,请使用LINQ

var removeList = myDictionary.Where(pair => pair.Key > 1).Select(k => k.Key).ToList();

然后从列表中删除它们。

// remove from the main collection
foreach (var key in removeList)
{
    myDictionary.Remove(key);
}

答案 2 :(得分:2)

通常不支持迭代期间列表上的操作。预期的行为是抛出异常,但即使集合无法执行此操作,您也不能依赖于此工作。

您可以先将这些元素复制到另一个列表中,然后迭代这个要修改的新项目列表。

答案 3 :(得分:2)

没有。抛出InvalidOperationExcpetion。我同意已经枚举的项目可能是可删除的,因为有一个固定的索引。但问题如下:

SortedList的实现不够聪明,无法确定删除对枚举的进一步执行没有影响。为了保持简单和良好的表现,它不应该。

答案 4 :(得分:2)

其他人已经指出它不起作用。但是,由于集合是SortedList,因此您可以使用RemoveAt方法。

此方法具有稍好的内存配置文件,因为它不需要开销,而使用单独的列表来跟踪删除的O(n)增加。它也将具有O(n ^ 2)性能简档而不是O(n ^ 2 * log(n))。 RemoveAt方法是O(n),因为它必须执行数组复制。 Remove方法在内部调用RemoveAt之前添加O(log(n))操作以查找索引。所有这一切都可能与您无关,但如果遇到涉及大量“n”的情况,这一点很有用。

var myDictionary = new SortedList<decimal, string>();

// omitted code

int i = 0;
while (myDictionary.Count > 0 && i < myDictionary.Count)
{
  if (/* predicate to use for removal */)
  {
    myDictionary.RemoveAt(i);
  }
  else
  {
    i++;
  }
}

答案 5 :(得分:0)

另一种解决方案:

            int counter= MyDictionary.Count;
            if (counter == 0)
                return;

            for (int i = 0;  i < counter;i++)
            {
                KeyValuePair<MyIdentifier, MyValue> key = (KeyValuePair<MyIdentifier, MyValue>)MyDictionary.ToArray()[i];
                MyIdentifier identifier = null;

                if (key.Key != null)
                    identifier = key.Key as MyIdentifier;

                if (identifier != null)
                    if (MyCondition)
                    {
                        MyDictionary.Remove(identifier);
                        counter--;
                    }
            }