【C# 教程系列第 28 篇】System.InvalidOperationException:“Collection was modified

151 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

这是【C# 教程系列第 28 篇】,如果觉得有用的话,欢迎关注专栏。

一:问题描述

在 foreach 里对一个 List 列表执行 Add 或者 Remove 操作时,如下代码所示

class Program
{
    static List<string> nameList = new List<string>();

    static void Main(string[] args)
    {
        nameList.Add("苏醒");
        nameList.Add("AllenSu");

        foreach (var name in nameList)
        {
        	nameList.Add("庆余年");	// 添加
            nameList.RemoveAt(0);	// 移除
        }
        Console.ReadKey();
    }
}

会报如下错误。

在这里插入图片描述

二:解决方案

将 foreach 改为 for 循环即可,如下代码所示

for (int i = 0; i < nameList.Count; i++)
{
	nameList.Add("庆余年");
    nameList.RemoveAt(0);
}

三:发生原因

网上搜了一些相关资料,有的讲的太深,有的讲的太多都不想看下去,这里我简单整理了几个重要的地方,仅供参考。

参考一:

因为 foreach 内部使用的是 Iterator(迭代器),内部代码先判断是否 hasNext,然后再去调用 next,这两个函数是引起问题的关键。

参考二:

使用 foreach 遍历列表或者字典时,如果执行 Add 或者 Remove 操作或者给 item 某个属性赋值都会有这个错误。

因为返回的 IEnumerator 把当前的属性暴露为只读属性,所以对其的修改会导致运行时错误。

特例:

如果你在 foreach 中批量执行添加或者移除操作时,会引起该错误,不过如果你只对第一个元素执行操作,操作之后并执行 break ,是不会引起这个错误的。

比如这里我在 foreach 中执行添加操作后,直接 break 掉,并打印此时列表的个数,如下代码所示

static void Main(string[] args)
{
	nameList.Add("苏醒");
    nameList.Add("AllenSu");

    foreach (var name in nameList)
    {
     	nameList.Add("庆余年");
        break;
    }
    
    Console.Write(nameList.Count);   
    Console.ReadKey();
}

控制台运行结果如下

在这里插入图片描述

不过,实际中谁也不会在循环里执行一次操作,这里也就是测试才会这样去写。

你的问题得到解决了吗?欢迎在评论区留言。

赠人玫瑰,手有余香,如果觉得文章不错,希望可以给个一键三连,感谢。


结束语

技术是一点一点积累的,大神也不是一天就可以达到的。原地不动就是退步,所以每天进步一点点。

最后,附上一句格言:"好学若饥,谦卑若愚",望共勉。