数据行错误,集合已被修改;枚举操作可能无法执行。

11

我有一个 for-each 循环,在其中更新了数据行,因此会生成异常 "Collection was modified; enumeration operation might not execute"。有什么方法可以解决吗?我已经尝试使用 To-List 函数,但它不能与数据行一起使用。以下是我的代码:

foreach (DataRow row in dataTable.Rows) {
  temp = row[0].ToString();
  foreach (DataRow rows in dataTable.Rows) {
    if (temp == rows[0].ToString()) {
      tempdatatable.Rows.Add(row[0],row[1]);
      dataTable.Rows.Remove(rows);
      //Update happens here
    }
    tempdatatable.DefaultView.Sort = "gscitations DESC";
    dataGridView1.DataSource = tempdatatable;
  }
}

请尝试使用for代替foreach - Parimal Raj
请帮忙,我该如何使用for循环?我已经尝试过了,但是数据表无法通过索引遍历。 - mani
肯定可以!https://dev59.com/12Up5IYBdhLWcg3wLVOn#15457712 - Parimal Raj
看起来这个问题是特定于DataRowCollection.Remove(),并在备注中记录在: DataRowCollection.Remove(DataRow) Method - gridtrak
3个回答

11

在使用 foreach 语句枚举集合时,如果同时修改该集合,则会在“幕后”使用 Enumerator 对象进行枚举(MDSN 链接)。这是不允许的。

解决此问题的一种可能方式是,在第一次枚举时收集要删除的行,然后在单独的循环中将它们删除,代码如下:

var rowsToDelete = new List<DataRow>();

foreach (DataRow row in dataTable.Rows)
     {
         temp = row[0].ToString();
         foreach (DataRow rows in dataTable.Rows)
         {
             if (temp == rows[0].ToString())
             {
                 tempdatatable.Rows.Add(row[0],row[1]);
                 rowsToDelete.Add(rows);
             }
             tempdatatable.DefaultView.Sort = "gscitations DESC";
             dataGridView1.DataSource = tempdatatable;
         }
     }

rowsToDelete.ForEach( x => dataTable.Rows.Remove(x) );

您也可以使用for循环替换foreach循环,但是需要额外处理当前索引以正确删除元素。


但是如果我在循环后删除那些行,那就不好了,因为我有25万条记录,如果每次它找到匹配项并且不删除它,它将一遍又一遍地搜索,所以这将需要时间,所以我希望它删除匹配的行。 - mani

4

尝试这个:

for (int i = 0; i < dataTable.Rows.Count; i++)
{
    var tempRow = dataTable.Rows[i];
    var temp = dataTable.Rows[i][0];
    for (int j = 0; j < dataTable.Rows.Count; j++)
    {
        DataRow rows = dataTable.Rows[j];
        if (temp == rows[0].ToString())
        {
            tempdatatable.Rows.Add(tempRow[0], tempRow[1]);
            dataTable.Rows.Remove(rows);      //Update happen here
        }
        tempdatatable.DefaultView.Sort = "gscitations DESC";
        dataGridView1.DataSource = tempdatatable;
    }
}

第二行出现datatable错误,索引不能与datatable一起使用。 - mani
@mani - 已修复,是一个打字错误! - Parimal Raj
@mani - 第二行和第三行已更改。 - Parimal Raj
2
一个更简单的解决方法是将你的dataTable.Rows更改为dataTable.Select(""),这样你就不必担心创建for循环了。http://codingcramp.blogspot.com/2014/10/collection-was-modified-enumeration.html有一个非常好的例子。 - Dan

0
我会建议你制作一个单独的条目表,而不是调用datatable.Rows.Remove(rows),将行“rows”添加到另一个表中。然后,每当行或行迭代时,运行if语句来检查它是否已被“删除”,即在删除行列表中。枚举结束后,您可以永久从表中删除这些行。
编辑:
以下是代码实现:
DataTable duplicates = dataTable;
duplicates.Rows.Clear(); /* Produces an empty duplicate of the 
dataTable table to put the duplicates in */
foreach (DataRow row in dataTable.Rows)
{
     if (!duplicates.Rows.Contains(row))
     {    
         temp = row[0].ToString();
         foreach (DataRow rows in dataTable.Rows)
         {
             if (temp == rows[0].ToString()&&!duplicates.Rows.Contains(rows)) //need unique key
             {
                 tempdatatable.Rows.Add(row[0],row[1]);

             }
             tempdatatable.DefaultView.Sort = "gscitations DESC";
             dataGridView1.DataSource = tempdatatable;
         }
    }
}
foreach (DataRow row in duplicates.Rows)
{
    dataTable.Rows.Remove(row);
}

如果您没有唯一的键,可以尝试将!duplicates.Rows.Contains(/*specific row*/)替换为duplicates.Rows.IndexOf(/*specific row*/)>0。这应该提供一个足够的替代方案。

尝试这个简短而简单的解决方案:foreach (DataRow row in dataTable.Select("")) { if (row["TABLE_NAME"].ToString().Contains("FilterDatabase")) dataTable.Rows.Remove(row); } - Thamarai T

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