2010-02-26 69 views
34

我不明白为什么这段代码不起作用。安全删除DataRow在ForEach

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

似乎为我工作。我猜dataTable.Rows.Remove(dataRow);虽然不起作用。 – synergetic 2014-05-02 07:25:48

回答

31

.NET中的大多数集合都不允许您在迭代集合时更改集合的内容。从docs for IEnumerator

一个枚举仍然有效的,只要 集合保持不变。如果 变化对集合进行,如添加,修改或删除 元件例如 ,枚举是 失效且不可恢复和下一 呼叫对MoveNext或重置引发 InvalidOperationException异常。如果 集合在 MoveNext和Current之间修改,则当前返回 它设置的元素,即使枚举器已经失效 。

最好的解决办法通常是创建要删除的项目的一个单独的集合(例如List<DataRow>),然后将其删除后,你已经完成迭代。

1

Rows内容的变化,如果你删除一个行,这使得迭代无效,而你是迭代。

但是,您可以先将行复制到集合中,然后迭代集合并删除行。这可以确保迭代不会因更改要迭代的数据而中断。

+0

我该如何做到这一点? – 2010-02-26 12:56:18

0

这适用于几乎任何收藏。如果您在循环收集时尝试删除某个项目,则会遇到问题。例如,如果删除第3行,则前一行#4变为第3行。

18

您在使用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(); 
} 
+6

不正确。用“foreach”迭代时不能修改集合您可以使用标准的for循环。例如:'for(int i = datatable.Rows.length - 1; i> = 0; i - ){//移除行}' – AllenG 2010-04-19 16:20:11

+0

@AllenG:谢谢,我添加了信息。 – 2010-04-19 17:34:28

+0

迭代时删除是可能的http://stackoverflow.com/questions/3150216/data-table-delete-a-row-in-c-using-loop – Developer 2010-06-30 14:49:58

0

使用此:

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

{ 

myDataTable[i].Delete(); 

} 
+3

你实际上想以另一种方式来做到这一点''(int i - mydatatable.rows.count -1; i> = 0; i - )'你的方式可能会导致行被跳过(并且根据我的经验,通常会 – AllenG 2010-04-19 16:21:12

40

最保险的办法 - 使用for

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

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

datatable.AcceptChanges(); 
+3

+1好于创建另一个副本并进行更改 – 2012-07-16 21:01:34

+1

不错,使用'datatable.AcceptChanges()'真正删除行,否则它们仍然在数据表中 - RowState为'deleted' – peter 2015-05-06 11:36:54

+0

已更新答案 – VMAtm 2015-05-06 12:15:40

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()方法。

4

可能是我的答案不再有用。在使用的foreach的DataRow 异常抛出只出现在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

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

dataTable.AcceptChanges(); 

请参考捕捉到understatnd它的工作之前,通过这个问题,你可以调用DataTable.AcceptChanges()。

  1. 刚刚删除但未从DataTable中删除。

enter image description here

  • 分段的AcceptChanges前点()函数。 enter image description here
  • 执行AcceptChanges()函数后。 enter image description here
  • 我希望现在解决这个问题。

    +2

    我同意你的回答,但是你如何解释这个:http://msdn.microsoft.com/en-us/library/system.data.datarow.delete.aspx“删除不应该在一个foreach中调用在迭代thr时循环一个DataRowCollection对象。删除将修改集合的状态。“MSDN文档中的错误? – Eternal21 2014-10-12 19:38:54

    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 
    
    0

    有一个其它版本的软件(我认为更容易),我只是用:

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

    这更快。

    0

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

    希望这可以帮助某人...

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

    这是因为它看起来像试图拆卸你爬楼梯的楼梯。简单地说,你不能删除你迭代的项目。

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

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

    当然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++;   
        } 
    } 
    
    +0

    **来自复审队列**:我可以请求您请您在答案中添加更多上下文,仅用于代码的答案很难理解,它将有助于提问者和未来的读者,如果你可以在你的文章中添加更多的信息。 – RBT 2017-05-10 09:22:24