C#Collection被修改了;

C# Collection was modified; enumeration operation may not execute

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Collection was modified; enumeration operation may not execute

你好,

我正在创建一个项目估算程序,并收到以下错误:C集合已修改;枚举操作可能无法执行。

与使用此相关:我在全球范围内通过以下方式初步宣布该裁决:

1
Dictionary<int, int> rankings = new Dictionary<int, int>();

包含此字典的下一个方法执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void getFirstEstimation()
{
    List<int> array = new List<int>();

    string strConnection = ConfigurationSettings.AppSettings["ConnectionString"];
    MySqlConnection connection = new MySqlConnection(strConnection);
    MySqlCommand command = connection.CreateCommand();
    MySqlDataReader reader;
    command.CommandText ="SELECT idprojects FROM `test`.`projects` WHERE application_layers =" + applicationTiers;
    connection.Open();

    reader = command.ExecuteReader();
    while (reader.Read())
    {
        array.Add(Convert.ToInt32(reader["idprojects"].ToString()));
    }
    foreach (int i in array)
    {
        rankings[i] = 15;
    }
    connection.Close();
}

我在这里第二次这么叫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
private void getSecondEstimation()
{
    Dictionary<int, string> sqltext = new Dictionary<int, string>();
    Dictionary<int, int> valueForSql = new Dictionary<int, int>();
    Dictionary<int, int> weightings = new Dictionary<int, int>();
    sqltext.Add(1,"project_type");
    valueForSql.Add(1, projectType);
    weightings.Add(1, 10);
    sqltext.Add(2,"application_domain");
    valueForSql.Add(2, applicationDomain);
    weightings.Add(2, 8);
    sqltext.Add(3,"organisation_size");
    valueForSql.Add(3, organizationSize);
    weightings.Add(3, 8);
    sqltext.Add(4,"no_of_locations");
    valueForSql.Add(4, noOfLocations);
    weightings.Add(4, 7);
    sqltext.Add(5,"development_process");
    valueForSql.Add(5, developmentProcess);
    weightings.Add(5, 6);
    sqltext.Add(6,"rules_engine");
    valueForSql.Add(6, rulesEngine);
    weightings.Add(6, 5);
    sqltext.Add(7,"middleware");
    valueForSql.Add(7, middleware);
    weightings.Add(7, 4);
    sqltext.Add(8,"location_of_development");
    valueForSql.Add(8, locationOfDevelopment);
    weightings.Add(8, 3);
    sqltext.Add(9,"programming_language");
    valueForSql.Add(9, programmingLanguage);
    weightings.Add(9, 3);
    sqltext.Add(10,"development_environment");
    valueForSql.Add(10, developmentEnvironment);
    weightings.Add(10, 3);
    sqltext.Add(11,"backend");
    valueForSql.Add(11, backend);
    weightings.Add(11, 3);
    sqltext.Add(12,"webserver");
    valueForSql.Add(12, webServer);
    weightings.Add(12, 3);

    List<int> array = new List<int>();

    string strConnection = ConfigurationSettings.AppSettings["ConnectionString"];
    MySqlConnection connection = new MySqlConnection(strConnection);
    MySqlCommand command = connection.CreateCommand();
    MySqlDataReader reader;

    for (int i = 1; i <= 12; i++)
    {
        command.CommandText ="SELECT idprojects FROM `test`.`projects` WHERE" + sqltext[i] +" =" + valueForSql[i];
        connection.Open();
        //int testInt;
        reader = command.ExecuteReader();
        while (reader.Read())
        {
            array.Add(Convert.ToInt32(reader["idprojects"].ToString()));
        }
        foreach (int a in array)
        {
            if (!rankings.ContainsKey(a))
            {
                rankings[a] = 0;
            }
            rankings[a] = rankings[a] + weightings[i];
        }
        connection.Close();
    }      
}

问题出现在代码的这个区域:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private void getThirdEstimation()
{
    ArrayList tempModuleHolder;

    string strConnection = ConfigurationSettings.AppSettings["ConnectionString"];
    MySqlConnection connection = new MySqlConnection(strConnection);
    MySqlCommand command = connection.CreateCommand();
    MySqlDataReader reader;
    int similarModules;

    foreach (KeyValuePair<int, int> kvp in rankings)
    {
        similarModules = 0;
        tempModuleHolder = new ArrayList();
        command.CommandText ="SELECT id_modules FROM `test`.`modules_in_project` WHERE id_project =" + kvp.Key;
        connection.Open();

        reader = command.ExecuteReader();
        while (reader.Read())
        {
            tempModuleHolder.Add(Convert.ToInt32(reader["id_modules"].ToString()));
        }

        foreach (int i in tempModuleHolder)
        {
            if(modules.Contains(i))
            {
                similarModules++;
            }
        }
        if((double)(similarModules/modules.Count)>0.6)
        {
            //kvp.Value = kvp.Value + 4;
            rankings[kvp.Key] = rankings[kvp.Key] + 4;
        }
        connection.Close();
    }
}

如果有任何帮助解决问题,我们将不胜感激。


在迭代期间,不能修改使用foreach迭代的任何集合。

因此,当您在排名上运行foreach时,您不能修改它的元素、添加新的元素或删除任何元素。


该错误确切地告诉您问题是什么(在调试器中运行或读取堆栈跟踪将确切地告诉您问题在哪里):

C# Collection was modified; enumeration operation may not execute.

你的问题是循环

1
2
3
foreach (KeyValuePair<int, int> kvp in rankings) {
    //
}

其中修改了集合rankings。特别是进攻线是

1
rankings[kvp.Key] = rankings[kvp.Key] + 4;

在进入循环之前,请添加以下行:

1
var listOfRankingsToModify = new List<int>();

将违规行替换为

1
listOfRankingsToModify.Add(kvp.Key);

在你退出循环之后

1
2
3
foreach(var key in listOfRankingsToModify) {
    rankings[key] = rankings[key] + 4;
}

也就是说,记录需要进行的更改,并在不迭代需要修改的集合的情况下进行更改。


正如其他人指出的,您正在修改一个正在迭代的集合,这就是导致错误的原因。违规代码如下:

1
2
3
4
5
6
7
8
9
foreach (KeyValuePair<int, int> kvp in rankings)
{
    .....

    if((double)(similarModules/modules.Count)>0.6)
    {
        rankings[kvp.Key] = rankings[kvp.Key] + 4;  // <--- This line is the problem
    }
    .....

上面代码中不明显的是Enumerator的来源。在几年前关于EricLippert的一篇博客文章中,提供了一个示例,说明编译器将foreach循环扩展到了什么程度。生成的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator(); // <-- This
                                                       // is where the Enumerator
                                                       // comes from.
    try
    {
        int m; // OUTSIDE THE ACTUAL LOOP in C# 4 and before, inside the loop in 5
        while(e.MoveNext())
        {
            // loop code goes here
        }
    }
    finally
    {
      if (e != null) ((IDisposable)e).Dispose();
    }
}

如果您在msdn文档中查找IEnumerable(这是GetEnumerator()返回的),您将看到:

Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection.

这使我们回到错误消息的状态,而其他答案的状态,您正在修改基础集合。


我怀疑错误是由以下原因引起的:

1
foreach (KeyValuePair<int, int> kvp in rankings)

排名是一本字典,它是IEnumerable。通过在foreach循环中使用它,可以指定要延迟地从字典中获取每个keyValuePair。也就是说,在循环再次迭代之前,不会返回下一个keyValuePair。

但你在修改循环中的字典:

1
rankings[kvp.Key] = rankings[kvp.Key] + 4;

这是不允许的…所以你得到了例外。

你可以这么做

1
foreach (KeyValuePair<int, int> kvp in rankings.ToArray())

问题在于您执行的位置:

1
rankings[kvp.Key] = rankings[kvp.Key] + 4;

不能在foreach循环中修改正在迭代的集合.forEach循环要求循环在迭代期间是不可变的。

相反,使用一个标准的"for"循环,或者创建一个新的循环,这个循环是一个副本,并在更新原始循环的同时对其进行迭代。