收集被修改;枚举操作可能无法执行。“不修改集合元素

时间:2011-03-31 09:05:34

标签: c#

我的代码中有一个嵌套循环“结构”。有时候,我收到以下信息。

  

收藏被修改;枚举操作可能无法执行。

我有一个我正在循环的集合,如下所示。 CollList<string>

foreach (string[] s1 in obj.Coll
{
    foreach (string s in s1) { }
}

对于数组中的每个字符串,我需要使用它(读取为读取值,而不是写入)。 我所做的就是获取目录(这个值是路径)并将此字符串拆分为数组。

如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

在您枚举时obj.Coll已更改。如果当前线程未更改它,则可能由其他某个线程更改。如果当前线程更改了集合,则基本上有两种方法可以解决问题:您可以创建集合的副本并枚举副本,也可以推迟更改,直到您枚举集合为止。

但是,如果集合被另一个线程更改,则应该以线程安全的方式访问集合(不仅仅是在这里,而是在所有地方)。

Kieren Johnstone的

编辑

我写了一个简短的代码来证明List<T>.ToArray()不是线程安全的。

var list = new List<int>();

Task.Factory.StartNew(() => {
    for (int i = 0; i < 1000000; ++i) {
        list.Clear();

        // Add values from 1 to 9
        for (int j = 1; j < 10; ++j) {
            list.Add(j);
        }
    }

    Console.WriteLine("Thread Exit: list.Add()");
});

Task.Factory.StartNew(() => {
    for (int i = 0; i < 100; ++i) {
        var array = list.ToArray();
        if (array.Length > 0) {
            Console.WriteLine("ToArray(): {0}", string.Join(", ", array));
        }
    }

    Console.WriteLine("Thread Exit: list.ToArray()");
});

以下是输出的片段。我想这证明了我的主张。该代码段包含15行,其中9行包含错误数据。

ToArray(): 1, 2, 3, 4
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4, 5, 6, 7, 0, 0
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0
ToArray(): 0, 0, 0, 4, 5, 6, 7
ToArray(): 1, 2, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3
ToArray(): 1, 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2
ToArray(): 1, 2, 3
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4
ToArray(): 1, 2, 3, 4, 5, 6, 7, 8

如果我们使用list.Insert(0, j)代替list.Add(j),会有更多变化。

答案 1 :(得分:0)

您可以尝试:

foreach (string[] s1 in obj.Coll.ToArray())
{

在开始迭代之前需要复制一份!