集合已被修改;枚举操作可能无法执行。

5

这个问题在论坛中经常被问到。我知道如何解决这个问题。但是我很好奇为什么"枚举操作无法在集合修改时执行"

        List<string> list = new List<string>();

        list.Add("a");

        list.Add("b");

        int[] array = new int[6] { 1, 2, 3, 4, 5, 5 };

        HashSet<int> hashSet = new HashSet<int>();

        int i = 0;

        foreach (string s in list)
        {
            list[i] = "test";

            i++;
        }

但是当我将list更改为list.toarray时,它就可以工作了。

3个回答

8
一般来说,.Net集合不支持同时枚举和修改。行list[i] = "test"在枚举集合list时修改它,因此会生成异常。尽管这是一次微不足道的修改,不影响列表结构,但List<T>将即使是原地修改视为破坏性操作。 ToArray版本之所以可行,是因为现在有两个集合:
  1. list
  2. 创建的数组
实际上,您正在枚举数组,因此修改原始的list是可以的。

有什么想法吗?http://stackoverflow.com/questions/36215695/not-able-to-dispose-datatable-in-foreach-loop/36215822?noredirect=1#comment60064209_36215822? - Neel

7
微软规定,任何实现iEnumerable接口的对象在修改时必须取消任何现有的枚举。这个要求的一般原因是对于许多类型的集合来说,在修改集合时很难确保枚举器的行为是明智的。例如,假设一个List包含五个值(A、B、C、D、E),并且一个枚举器通过设置n为元素数量,然后输出element(0)、element(1)等,直到element(n-1)来工作。如果在枚举器枚举element(2)[即C]时插入一个元素BB在element(1)[即B]之后,则枚举器可能继续输出element(3)[仍然是C],然后输出element(4)[D],然后决定完成,因为它输出了所有五个元素。这将是一个糟糕的情况(一个元素出现两次,一个元素消失)。
如果修改集合会阻止枚举器产生明智的结果,那么使枚举器无效是合理的。但是,在我的看法中,即使集合被修改,能够满足以下契约的枚举器也应该这样做,而不是抛出异常:
1. 在整个枚举期间存在的任何项目必须恰好返回一次。 2. 在枚举期间部分存在的任何项目必须恰好返回一次或不返回,但没有关于返回哪些这样的项目(如果有)的要求。 3. 返回项目的顺序必须是枚举器的有效顺序(例如,SortedList必须按排序顺序返回项目;如果向列表中添加一个在已输出项之前的项,该项不得被枚举)。 4. 对于(1)和(2),即使键相同,移除的项也应被视为与添加的项不同;如果更改了项的键,则在更改之前的项被认为与更改后的项不同。 5. 不能保证通过Reset进行的重复枚举将返回相同的项。
VB6风格的Collection似乎符合上述语义,但其他标准集合都不符合。太糟糕了——某些数据结构可以很好地满足这些要求,但根据当前规则,会频繁地复制列表数据,这些要求足以避免这种情况。

有没有对此的想法?http://stackoverflow.com/questions/36215695/not-able-to-dispose-datatable-in-foreach-loop/36215822?noredirect=1#comment60064209_36215822 - Neel

2
当你在foreach中使用list.ToArray()时,你会复制整个列表内容,并枚举复制品。在枚举列表时,你不再对列表进行更改。
这样做:
foreach (string s in list.ToArray())
{
   list[i] = "test";
   i++;
}

实际上,这与执行以下操作相同:

string[] newArray = list.ToArray();
foreach (string s in newArray)
{
   list[i] = "test";
   i++;
}

请注意,在第二种情况下,您不是枚举正在修改的集合,而是一个全新的集合。

有什么想法吗?http://stackoverflow.com/questions/36215695/not-able-to-dispose-datatable-in-foreach-loop/36215822?noredirect=1#comment60064209_36215822? - Neel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接