web-dev-qa-db-ja.com

ForEachでDataRowを安全に削除する

このコードが機能しない理由がわかりません。

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

たとえ DataRow.Deleteはコレクションの状態を変更しません。 Microsoftのドキュメント は、コレクションを繰り返し処理している間は呼び出してはならないことを示しています。

DataRowCollectionオブジェクトを反復処理している間、foreachループでDeleteもRemoveも呼び出さないでください。削除または削除は、コレクションの状態を変更します。

通常、最善の解決策は、個別のコレクションを作成することです(例:List<DataRow>)削除したいアイテムを削除し、イテレーションを終了した後after削除します。

これは、コレクションからアイテムを削除する場合のソリューションでもあります。NETのほとんどのコレクションでは、コレクションの繰り返し中にコレクションの内容を変更することはできません。

31
Jon Skeet

最も安全な方法-forループを使用

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

AcceptChanges を忘れずに、すべてのマークされた行を削除します。

datatable.AcceptChanges();
49
VMAtm

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

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

8
Chris

もはや役に立たない私の答えかもしれません。 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を使用する前にDataTable.AcceptChanges()を呼び出すことができます

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

dataTable.AcceptChanges();

スナップショットを参照して、動作を確認してください。

  1. 削除されただけですが、DataTableからは削除されません。

enter image description here

  1. AcceptChanges()関数の前のブレークポイント。 enter image description here
  2. AcceptChanges()関数を実行した後。 enter image description here

この問題が解決したことを願っています。

2

私がちょうど使用したものの他のバージョンがあります(私はもっと簡単だと思います):

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

これは高速です。

1
Jettero

私のような特定のシナリオを探している人にのみ、所要時間を短縮する必要があり、いくつかの有用な情報が各行から抽出されたら、削除済みとしてマークして行を除外しました。

これが誰かを助けることを願っています...

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

これを実現する最も簡単な方法は、リストを使用して削除する行をマップし、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
1
Nishantha

1行削除すると、反復中にRowsコンテンツが変更され、反復が無効になります。

ただし、最初に行をコレクションにコピーしてから、コレクションを反復処理し、その方法で行を削除できます。これにより、反復するデータを変更しても反復が中断されないようになります。

1
Lucero

これは、登る階段の階段を分解しようとするように見えるためです。単純に、反復するアイテムを削除することはできません。

したがって、異なる配列を使用して、データテーブルのRowsプロパティから反復して削除する必要があります。

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

アイテムに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;
}
_

オブジェクトがFileInfo(IIRC)のような.GetXXXX()コレクションを持っている場合、foreach内のアイテムのコンテンツを削除することができます。私が検討した解決策の1つは、.GetItems()メソッドを提供する拡張メソッドを作成することです。

0
IAbstract

確かな魔術師

これは私がそれをやった方法であり、正常に動作します

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
Sam

これを使って:

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

{

 myDataTable[i].Delete();

}
0
1111

これは、ほとんどすべてのコレクションに適用されます。コレクションをループしているときにアイテムを削除しようとすると、問題が発生します。たとえば、行#3を削除すると、前の行#4は行#3になります。

0
DOK