【问题标题】:C# Collection was modified; enumeration operation may not execute [duplicate]C# Collection 被修改;枚举操作可能无法执行
【发布时间】:2011-09-04 21:11:03
【问题描述】:

可能重复:
Collection was modified; enumeration operation may not execute

你好,

我正在创建一个项目估算程序并收到以下错误:C# Collection was modified;枚举操作可能无法执行。

它与使用此有关: 我首先在全球范围内声明字典:

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

包含此字典的 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();
}

我在这里第二次调用它:

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();
    }       
}

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

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();
    }
}

对于问题所在的任何帮助将不胜感激

【问题讨论】:

  • 顺便说一句,题外话,你的 MySqlConnection 和 MySqlDataReader 类没有实现 IDisposable 到 Dispose() 方法,所以你可以在连接和阅读器周围使用 using 块?
  • @ydobonmai: MySqlConnectionMySqlDataReader 可能是指 MySql.Data.MySqlClient 使用 MySQL 数据库的类。因此,它们确实实现了IDisposable,并且它们的使用应该包装在using 块中。

标签: c# collections dictionary


【解决方案1】:

您使用 foreach 迭代的任何集合在迭代期间都不得修改。

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

【讨论】:

  • 您可以循环浏览该集合的副本。例如循环实例中的Collection.ToArray()。这将允许您在循环中修改您的实际集合,同时不更改集合的“副本”。来源stackoverflow.com/questions/604831/…
  • +1 Don: ToArray() 修复它。也向@Roy +1。
  • 我想知道为什么这个错误还没有修复。
【解决方案2】:

错误告诉你问题到底出在哪里(在调试器中运行或读取堆栈跟踪会告诉你问题出在哪里):

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

你的问题是循环

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

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

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

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

var listOfRankingsToModify = new List<int>();

将有问题的行替换为

listOfRankingsToModify.Add(kvp.Key);

退出循环后

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

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

【讨论】:

    【解决方案3】:

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

    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 的来源。在来自few years back about 的博客文章中,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();
        }
    }
    

    如果您查看 IEnumerable 的 MSDN 文档(这是 GetEnumerator() 返回的内容),您会看到:

    枚举器可用于读取集合中的数据,但不能用于修改底层集合。

    这使我们回到错误消息状态和其他答案重新声明的内容,您正在修改基础集合。

    【讨论】:

    • 潜在读者:请忽略不赞成票,这是在书呆子气中完成的。 ROMAN:如果你编辑这个答案,我会删除不赞成票,它已经过了时间限制,不会让我这样做。
    【解决方案4】:

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

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

    rankings 是一个字典,它是 IEnumerable。通过在 foreach 循环中使用它,您指定您希望字典中的每个 KeyValuePair 以延迟的方式。也就是说,直到您的循环再次迭代,才会返回下一个 KeyValuePair。

    但是您正在修改循环内的字典:

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

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

    你可以这样做

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

    【讨论】:

      【解决方案5】:

      问题在于你在哪里执行:

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

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

      改为使用标准的“for”循环或创建一个新循环作为副本并在更新原始循环时对其进行迭代。

      【讨论】:

        猜你喜欢
        • 2016-06-06
        • 1970-01-01
        • 2021-02-25
        • 1970-01-01
        • 1970-01-01
        • 2012-04-13
        • 1970-01-01
        相关资源
        最近更新 更多