为了避免出现InvalidOperationException最佳实践:集合已修改? [英] Best practice to avoid InvalidOperationException: Collection was modified?

查看:242
本文介绍了为了避免出现InvalidOperationException最佳实践:集合已修改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很多时候我需要这样的事情:

 的foreach(以线线线)
 {
    如果(line.FullfilsCertainConditions())
    {
       lines.Remove(线)
    }
 }
 

这是不行的,因为我总是一 InvalidOperationException异常因为枚举器循环过程中发生了变化。

于是我改变了这样的我所有环路为以下内容:

 名单,其中,线>删除=新的名单,其中,线>();
的foreach(以线线线)
{
   如果(line.FullfilsCertainConditions())
   {
      remove.Add(线)
   }
}

的foreach(线路输入删除线){
{
   lines.Remove(线);
}
 

我不知道这是否真的是最好的方式,因为在最坏的情况下,我有超过原始列表迭代2倍,所以它需要n个时间2N,而不是。

有没有更好的方式来做到这一点?

编辑:

我是能够做到这一点使用马克的回答!但如果我的收藏不器具removeall过()?

例如一个

  

System.Windows.Controls.UIElementCollection

编辑2:

再次与马克的帮助,我现在可以进行以下调用来删除所有ScatterViewItems:

  Col​​lectionUtils.RemoveAll(manager.getWindow()IconDisplay.Items,ELEM => elem.GetType()== typeof运算(ScatterViewItem));
 

解决方案

这是直接烤成名单,其中,T>

  lines.RemoveAll(行=> line.FullfilsCertainConditions());
 

或C#2.0:

  lines.RemoveAll(委托(行线){
    返回line.FullfilsCertainConditions();
});
 


在非 - 名单,其中,T> 情况下(你编辑的问题),你可以换这个类似下面(未经测试):

 静态类CollectionUtils
{
    公共静态无效removeall过< T>(IList的< T>清单,predicate< T> predicate)
    {
        诠释计数= list.Count;
        而(count--大于0)
        {
            如果(predicate(名单[计数]))list.RemoveAt(计数);
        }
    }
    公共静态无效removeall过(IList的列表,predicate<对象> predicate)
    {
        诠释计数= list.Count;
        而(count--大于0)
        {
            如果(predicate(名单[计数]))list.RemoveAt(计数);
        }
    }
}
 

由于 UIElementCollection 实现(非通用)的IList 这应该工作。而且比较方便,用C#3.0,你可以添加一个的IList / 的IList< T&GT ; ,并把它作为一个扩展的方法。唯一需要说明的是,该参数的匿名法将对象,所以你需要转换它扔掉。

Very often I need something like that:

 foreach (Line line in lines)
 {
    if (line.FullfilsCertainConditions())
    {
       lines.Remove(line)
    }
 }

This does not work, because I always get a InvalidOperationException because the Enumerator was changed during the loop.

So I changed all my loops of this kind to the following:

List<Line> remove = new List<Line>();
foreach (Line line in lines)
{
   if (line.FullfilsCertainConditions())
   {
      remove.Add(line)
   }
}

foreach (Line line in remove) {
{
   lines.Remove(line);
}

I'm not sure if this is really the best way since in the worst case I have to iterate 2 times over the original list and so it needs time 2n instead of n.

Is there a better way to do this?

EDIT:

I was able to do that using Mark's answer!But what if my collection doesn't implements RemoveAll()?

For example a

System.Windows.Controls.UIElementCollection

EDIT 2:

Again with the help of Mark I'm now able to make the following call to remove all ScatterViewItems:

CollectionUtils.RemoveAll(manager.getWindow().IconDisplay.Items, elem => elem.GetType() == typeof(ScatterViewItem));

解决方案

This is baked directly into List<T>:

lines.RemoveAll(line => line.FullfilsCertainConditions());

or in C# 2.0:

lines.RemoveAll(delegate(Line line) {
    return line.FullfilsCertainConditions();
});


In the non-List<T> case (your edit to the question), you could wrap this something like below (untested):

static class CollectionUtils
{
    public static void RemoveAll<T>(IList<T> list, Predicate<T> predicate)
    {
        int count = list.Count;
        while (count-- > 0)
        {
            if (predicate(list[count])) list.RemoveAt(count);
        }
    }
    public static void RemoveAll(IList list, Predicate<object> predicate)
    {
        int count = list.Count;
        while (count-- > 0)
        {
            if (predicate(list[count])) list.RemoveAt(count);
        }
    }
}

Since UIElementCollection implements the (non-generic) IList this should work. And quite conveniently, with C# 3.0 you can add a this before IList / IList<T> and have it as an extension method. The only subtlety is that the parameter to the anon-method will be object, so you'll need to cast it away.

这篇关于为了避免出现InvalidOperationException最佳实践:集合已修改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆