在ForEach中安全删除DataRow

时间:2010-02-26 12:43:03

标签: c# ado.net datatable collections datarow

我不明白为什么这段代码不起作用。

foreach (DataRow dataRow in dataTable.Rows)
{
    if (true)
    {
        dataRow.Delete();
    }
}

15 个答案:

答案 0 :(得分:47)

最安全的方式 - 使用for循环

for (int i = datatable.Rows.Count - 1; i >= 0; i--) 
{
    if (true)
    {
        datatable.Rows[i].Delete();
    }
}

不要忘记AcceptChanges删除所有标记的行:

datatable.AcceptChanges();

答案 1 :(得分:32)

即使DataRow.Delete没有修改集合的状态,Microsoft documentation也指出在迭代集合时不应该调用它:

  

在迭代DataRowCollection对象时,不应在foreach循环中调用Delete或Remove。删除也不删除修改集合的状态。

最好的解决方案通常是创建一个单独的集合(例如List<DataRow>)要删除的项目,然后在完成迭代后删除它们

对于要从集合中删除项目的情况,这也是一种解决方案,因为.NET中的大多数集合都不允许您在迭代时更改集合的内容。

答案 2 :(得分:19)

在使用foreach语句对其进行迭代时,无法修改集合。

你可以尝试这样的事情:

List<DataRow> deletedRows = new List<DataRow>();

foreach (DataRow dataRow in dataTable.Rows)
{
    if(true) deletedRows.Add(dataRow);
}

foreach(DataRow dataRow in deletedRows)
{
    dataRow.Delete();
}

答案 3 :(得分:9)

如果你调用delete方法,你只需要在foreach循环之后调用你正在修改的表上的AcceptChanges()

foreach (DataRow dataRow in dataTable.Rows)
{
    if (true)
    {
        dataRow.Delete();
    }
}

dataTable.AcceptChanges();

delete方法只是标记要删除的行。

http://msdn.microsoft.com/en-us/library/system.data.datarow.delete%28v=VS.90%29.aspx

答案 4 :(得分:4)

可能是我的答案不再有用。 使用DataRow的Foreach中的异常抛出仅出现在.Net 2.0及更早版本中,原因在于msdn中的描述 http://msdn.microsoft.com/en-us/library/system.data.datarow.delete(v=vs.80).aspx

如果该行的RowState已添加,则该行将从表中删除。

使用Delete方法后,RowState变为Deleted。在您调用AcceptChanges之前,它仍会被删除。

通过调用RejectChanges可以取消删除已删除的行。

要传递此问题,您可以在使用foreach之前调用DataTable.AcceptChanges()

答案 5 :(得分:2)

foreach (DataRow dataRow in dataTable.Rows)
{
    if (true)
    {
        dataRow.Delete();
    }
}

dataTable.AcceptChanges();

请参阅快照以了解其工作情况。

  1. 刚刚删除但未从DataTable中删除。
  2. enter image description here

    1. AcceptChanges()函数之前的断点。 enter image description here
    2. Eexecuting AcceptChanges()函数之后。 enter image description here
    3. 我希望现在能解决这个问题。

答案 6 :(得分:1)

如果删除一行,则在迭代时Rows内容会发生更改,这会导致迭代无效。

但是,您可以先将行复制到集合中,然后遍历集合并删除那些行。这可以确保通过更改要迭代的数据来中断迭代。

答案 7 :(得分:1)

通过使用List映射要删除的行然后删除DataTable迭代之外的行来实现此目的的最简单方法。

C#

    List<DataRow> rowsWantToDelete= new List<DataRow>();

    foreach (DataRow dr in dt.Rows)
    {
        if(/*Your condition*/)
        {
            rowsWantToDelete.Add(dr);
        }
    }

    foreach(DataRow dr in rowsWantToDelete)
    {
        dt.Rows.Remove(dr);
    }

VB

Dim rowsWantToDelete As New List(Of DataRow)

For Each dr As DataRow In dt
    If 'Your condition' Then
        rowsWantToDelete .Add(dr)
    End If
Next

For Each dr As DataRow In rowsWantToDelete 
    dt.Rows.Remove(dr)
Next

答案 8 :(得分:1)

还有其他版本(我认为更容易)我刚才使用的内容:

int i=0;
while (i < myDataTable.Rows.Count)
{
    if (condition)  //should it be deleted?
        myDataTable.Rows.RemoveAt(i);
    else
        i++;
}

这更快。

答案 9 :(得分:1)

仅适用于寻找像我这样的特定场景的人 我需要缩短所花费的时间,一旦从每一行中提取了一些有用的信息,我就通过标记为已删除来排除该行。

希望这有助于某人...

foreach (DataRow dataRow in dataTable.Rows)
{
    if (dataRow.RowState != DataRowState.Deleted)
    {
        if (your condition here)
        {
            dataRow.Delete();
        }
    }
}

答案 10 :(得分:0)

这几乎适用于任何收藏品。如果您在循环浏览集合时尝试删除项目,则会出现问题。例如,如果删除第3行,则前一行#4将成为第3行。

答案 11 :(得分:0)

使用此:

for (int i = 0; i < myDataTable.Rows.Count; i++)

{

 myDataTable[i].Delete();

}

答案 12 :(得分:0)

如果项目有Count,那就是我所做的:

int Count = myTable.Rows.Count;

while (Count > 0) // replace condition with myTable.Rows.Count if unconditionally performed on all rows
{
    DataRow row = myTable.Rows[0] // or however you want to find your index

    // do some work
    myTable.Rows.Remove(row);

    // if you want to perform a check to break out of while
    if (someCondition)
        Count = 0;
    else
        Count = myTable.Rows.Count;
}

请注意,对象具有.GetXXXX()集合,例如FileInfo(IIRC), 删除foreach中的项目内容是可以接受的。我考虑过的一个解决方案是创建一个提供.GetItems()方法的扩展方法。

答案 13 :(得分:0)

这是因为它看起来像是要拆卸您攀爬的楼梯的楼梯。简单地说,您无法删除迭代的项目。

因此,您应该使用不同的数组来迭代并从数据表Rows属性中删除它们。

foreach (DataRow dataRow in dataTable.Select())
{
    if (true)
    {
        dataTable.Rows.Remove(dataRow);
    }
}

答案 14 :(得分:0)

Sure Magents

我就是这样做的,并且工作正常

dt = GetStationeryConsolidationDetails(txtRefNo.Text);
int intRows = dt.Rows.Count;
int x = 0;
for (int c = 0; c < intRows; c++)
{
  if (dt.Rows[c - x]["DQTY"].ToString() == "0")
  {
    dt.Rows[c - x].Delete();
    dt.AcceptChanges();
    x++;        
  }
}