C#Collection被修改了; 枚举操作可能无法执行

Gre*_*een 32 c# collections dictionary

可能重复:
收集已修改; 枚举操作可能无法执行

嗨,您好,

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

它与使用它有关:我最初在全球范围内声明了这个:

Dictionary<int, int> rankings = new Dictionary<int, int>();
Run Code Online (Sandbox Code Playgroud)

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

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();
}
Run Code Online (Sandbox Code Playgroud)

我在这里第二次叫它:

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();
    }       
}
Run Code Online (Sandbox Code Playgroud)

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

任何有关问题所在的帮助将非常感激

Roy*_*tus 90

在迭代期间,您可能无法修改使用foreach迭代的任何集合.

因此,当您在排名上运行foreach时,您无法修改其元素,添加新元素或删除任何元素.

  • 但是,您可以遍历集合的副本.例如,循环实例中的`Collection.ToArray()`.这将允许您在循环中修改实际集合,而不更改集合的"复制".来源http://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute (26认同)
  • +1 Don:ToArray()修复它.+1也是@Roy. (5认同)

jas*_*son 18

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

C#Collection被修改了; 枚举操作可能无法执行.

你的问题是循环

foreach (KeyValuePair<int, int> kvp in rankings) {
    //
}
Run Code Online (Sandbox Code Playgroud)

其中您修改集合rankings.特别是进攻线是

rankings[kvp.Key] = rankings[kvp.Key] + 4;
Run Code Online (Sandbox Code Playgroud)

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

var listOfRankingsToModify = new List<int>();
Run Code Online (Sandbox Code Playgroud)

用.替换违规行

listOfRankingsToModify.Add(kvp.Key);
Run Code Online (Sandbox Code Playgroud)

并在退出循环后

foreach(var key in listOfRankingsToModify) {
    rankings[key] = rankings[key] + 4;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,记录您需要进行的更改,并在不重复需要修改的集合的情况下进行更改.


R0M*_*RMY 13

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

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
    }
    .....
Run Code Online (Sandbox Code Playgroud)

从上面的代码可能不明显的是Enumerator它来自何处.在几年前的一篇博文中,Eric Lippert提供了一个foreach循环由编译器扩展到的例子.生成的代码如下所示:

{
    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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您查找IEnumerable的MSDN文档(GetEnumerator()返回的是什么),您将看到:

枚举器可用于读取集合中的数据,但不能用于修改基础集合.

这让我们回到错误消息的状态,其他答案重新陈述,您正在修改基础集合.


Jef*_*eff 7

我怀疑错误是由这引起的:

foreach (KeyValuePair<int, int> kvp in rankings)
Run Code Online (Sandbox Code Playgroud)

排名是一个字典,它是IEnumerable.通过在foreach循环中使用它,您将指定您希望以延迟方式从字典中获取每个KeyValuePair.也就是说,在循环再次迭代之前,不会返回下一个KeyValuePair.

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

rankings[kvp.Key] = rankings[kvp.Key] + 4;
Run Code Online (Sandbox Code Playgroud)

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

你可以这么做

foreach (KeyValuePair<int, int> kvp in rankings.ToArray())
Run Code Online (Sandbox Code Playgroud)