C#在遍历集合的同时,又要进行集合元素删除操作,怎么实现?会报错:集合已修改;可能无法执行枚举操作。

美奇开发工作室
企业官方账号
2020-04-22 09:29:41

//定义的集合
private Hashtable taskList = Hashtable.Synchronized(new Hashtable());
//遍历集合(集合是有数据的,我填充了)
if (taskList != null && taskList.Count > 0)
{
foreach (Object key in taskList.Keys)
{
//这里省略业务
}
}
//移除集合元素的方法
private void RemoveTask(int key)
{
if (taskList.Contains(key))
taskList.Remove(key);
}

下图是遍历的时候,报错:集合已修改;可能无法执行枚举操作。

请问各位大神有什么好的解决方法吗?
1、我换用过List<>集合,然后再用倒序删除,也会出现这样的问题,因为我要删除的元素不是固定的,不是删除最后一个元素,也不是删除第一个元素,而是删除任何一个元素。
2、我在想是不是可以在删除的时候,先给集合上锁?
...全文
1876 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
goodwell18 2020-04-26
  • 打赏
  • 举报
回复
hhhhhhh
  • 打赏
  • 举报
回复
引用 39 楼 Jef_Zhang 的回复:
[quote=引用 1 楼 手在键盘敲很轻 的回复:] 弄一个副本,比如两个list,一个是本体的,一个是副本,你可以遍历副本,根据得到的下标去操作本体
用下标是不对的.移除了一个之后,下标就变了[/quote]对,这个我也想到了
Jef_Zhang 2020-04-26
  • 打赏
  • 举报
回复
引用 1 楼 手在键盘敲很轻 的回复:
弄一个副本,比如两个list,一个是本体的,一个是副本,你可以遍历副本,根据得到的下标去操作本体
用下标是不对的.移除了一个之后,下标就变了
36度7 2020-04-23
  • 打赏
  • 举报
回复
顶,边看边学。
xiaoxiangqing 2020-04-23
  • 打赏
  • 举报
回复
不能在foreach里删除
m0_47293827 2020-04-23
  • 打赏
  • 举报
回复
for新问题又来了,索引递增越界异常,索引递减重复操作
luj_1768 2020-04-23
  • 打赏
  • 举报
回复
这种情况的正确实现应该是分两步操作:第一步先标记,第二步执行pack操作。显然是删除操作的底层实现考虑不周。
暗夜流岚 2020-04-23
  • 打赏
  • 举报
回复
你可以用for循环然后倒着来用 i--;
qq_36786068 2020-04-22
  • 打赏
  • 举报
回复
引用 3 楼 by_封爱 的回复:
不仅仅是Hashtable,就算你写的ArrayList 也会发生这种情况. 这种情况发生在 "并发操作"一个集合的时候 都会产生.. 因为你这不是线程安全的集合. 所以想实现的话 有2个方法.. 1`lock 2`使用线程安全的集合...
楼主已解决,就不要引申了,况且引申的都入坑了。正确解释,foreach 要用.GetEnumerator访问迭代器,迭代器要求不可修改。 所以他用for i 解决,和lock无关,和线程安全集合无关 既然你都引申了,我就说标准的正常人类的人性解。就是先find,后remove,不要因为所谓的性能问题,混在一起
by_封爱 版主 2020-04-22
  • 打赏
  • 举报
回复
不仅仅是Hashtable,就算你写的ArrayList 也会发生这种情况. 这种情况发生在 "并发操作"一个集合的时候 都会产生.. 因为你这不是线程安全的集合. 所以想实现的话 有2个方法.. 1`lock 2`使用线程安全的集合...
  • 打赏
  • 举报
回复
还是我自己解决了,这里分享一下我的经验:
1、把Hashtable换成ArrayList集合
2、删除时用倒序删除,同时弄个上锁标识,上锁后不允许线程遍历
3、删除完成后解锁

下面提供正确的代码:

//是否锁住集合
private bool look = false;
//删除集合操作
private void RemoveTask(int key)
{
look = true;
for (int i = taskList.Count - 1; i > -1; i--)
{
if (key == Convert.ToInt32(taskList[i]))
{
taskList.Remove(taskList[i]);
look = false;
break;
}
}
}
//遍历集合
if (taskList != null && taskList.Count > 0 && !look)
{
for (int i = 0; i < taskList.Count; i++)
{
//省略业务逻辑
}
}
ever_q 2020-04-22
  • 打赏
  • 举报
回复
hhhhhhh
  • 打赏
  • 举报
回复
弄一个副本,比如两个list,一个是本体的,一个是副本,你可以遍历副本,根据得到的下标去操作本体
No.4698888 2020-04-22
  • 打赏
  • 举报
回复
我觉得上楼说的比较可以
  • 打赏
  • 举报
回复
头一次发帖,大家这么热情,非常感谢!
我实际上是用了ThreadPool线程池的,我今天也做了黑盒测试,没有什么问题了。
方法肯定不只一种,但我比较偏向于简单又可以直接适用的,其实我也想过用2个数组集合,但后面还是觉得用一个就够了。下面贴出我实际项目里的主要代码,大家可以看看我项目的逻辑和项目需求,本人也只在北大青鸟学了一点C#的皮毛,有不太专业的地方,还请多多指教,再次感谢!!
代码放在博客文章里,链接地址:https://blog.csdn.net/qq15577969/article/details/105691224
wanghui0380 2020-04-22
  • 打赏
  • 举报
回复
倒是人家那位才是对滴,标准手法,先find,在remvoe
wanghui0380 2020-04-22
  • 打赏
  • 举报
回复

            Hashtable ht=new Hashtable();
            ht.Add("1","1");
            string[] t = new[] {"1", "2", "3"};
            foreach (var s in t)
            {
                if (ht.ContainsKey(s))
                    ht.Remove(s);

            }
qq_36786068 2020-04-22
  • 打赏
  • 举报
回复
不是啊 你新建一个数组撒,遍历的时候遍历一个,删除另外一个,有什么问题吗?有那么难? 是啊,不难啊。 要是直接 Array.Convert ,linq where.select 不是也一样。 楼主“what are you 弄啥捏”
  • 打赏
  • 举报
回复
引用 2 楼 美奇软件开发工作室 的回复:
还是我自己解决了,这里分享一下我的经验:
1、把Hashtable换成ArrayList集合
2、删除时用倒序删除,同时弄个上锁标识,上锁后不允许线程遍历
3、删除完成后解锁

下面提供正确的代码:

//是否锁住集合
private bool look = false;
//删除集合操作
private void RemoveTask(int key)
{
look = true;
for (int i = taskList.Count - 1; i > -1; i--)
{
if (key == Convert.ToInt32(taskList[i]))
{
taskList.Remove(taskList[i]);
look = false;
break;
}
}
}
//遍历集合
if (taskList != null && taskList.Count > 0 && !look)
{
for (int i = 0; i < taskList.Count; i++)
{
//省略业务逻辑
}
}



不是啊 你新建一个数组撒,遍历的时候遍历一个,删除另外一个,有什么问题吗?有那么难?
正怒月神 2020-04-22
  • 打赏
  • 举报
回复
foreach不允许删除和新增。 for循环可以 msdn对foreach的摘要写过:大意是,当枚举进行时,删除和新增元素,会抛异常。
// Returns an enumerator for this list with the given
        // permission for removal of elements. If modifications made to the list 
        // while an enumeration is in progress, the MoveNext and 
        // GetObject methods of the enumerator will throw an exception.
        //
        public Enumerator GetEnumerator() {
            return new Enumerator(this);
        }
加载更多回复(2)

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧