web-dev-qa-db-fra.com

Suppression en toute sécurité de DataRow dans ForEach

Je ne comprends pas pourquoi ce code ne fonctionne pas.

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

La plupart des collections dans .NET ne vous permettent pas de modifier le contenu de la collection pendant que vous parcourez celle-ci. À partir de docs pour IEnumerator :

Un énumérateur reste valable aussi longtemps que la collection reste inchangée. Si des modifications sont apportées à la collection, comme l'ajout, la modification ou la suppression de éléments, l'énumérateur est irrécupérablement invalidé et le prochain appel à MoveNext ou Reset lance un InvalidOperationException. Si la la collection est modifiée entre MoveNext et Current, Retours actuels l'élément sur lequel il est défini, même si l'énumérateur est déjà invalidé.

La meilleure solution consiste généralement à créer une collection distincte (par exemple, un List<DataRow>) d'éléments à supprimer, puis à les supprimer après que vous avez terminé d'itérer.

32
Jon Skeet

Le moyen le plus sûr - utilisez la boucle for

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

N'oubliez pas de AcceptChanges pour supprimer toutes les lignes marquées:

datatable.AcceptChanges();
47
VMAtm

Vous ne pouvez pas modifier une collection pendant une itération à l'aide d'une instruction foreach.

vous pouvez essayer quelque chose comme ça:

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

Si vous appelez la méthode delete, vous devez simplement appeler AcceptChanges() sur la table que vous modifiez, après la boucle foreach. 

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

dataTable.AcceptChanges();

La méthode delete marque simplement la ligne à supprimer.

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

9
Chris

peut-être ma réponse ne sera-t-elle plus utile… ... exception jeter dans Foreach avec DataRow n'apparaît que dans .Net 2.0 et versions antérieures, la raison en est la description dans msdn http://msdn.Microsoft.com/en-us /library/system.data.datarow.delete(v=vs.80).aspx

Si RowState de la ligne est Added, la ligne est supprimée du tableau.

RowState devient Deleted après avoir utilisé la méthode Delete. Il reste supprimé jusqu'à ce que vous appeliez AcceptChanges.

Une ligne supprimée peut être annulée en appelant RejectChanges.

pour résoudre ce problème, vous pouvez appeler DataTable.AcceptChanges () avant d’utiliser foreach.

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

dataTable.AcceptChanges();

S'il vous plaît se référer les clichés pour comprendre le fonctionnement de celui-ci.

  1. Juste supprimé mais non supprimé du DataTable.

enter image description here

  1. Point d'arrêt avant la fonction AcceptChanges () .enter image description here
  2. Après avoir exécuté la fonction AcceptChanges () .enter image description here

J'espère que ce problème est résolu maintenant.

2

Il existe une autre version de ce que je viens d’utiliser (je pense être plus facile):

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

Ce plus vite.

1
Jettero

Seulement pour les personnes qui recherchent un scénario spécifique comme moi, Je devais raccourcir le temps pris, et une fois que des informations utiles étaient extraites de chaque ligne, j’excluais la ligne en la marquant comme étant supprimé.

J'espère que cela aidera quelqu'un ...

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

Le moyen le plus simple d'y parvenir consiste à utiliser une liste pour mapper les lignes que vous souhaitez supprimer, puis supprimer des lignes en dehors de l'itération 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

Le contenu Rows change pendant l'itération si vous supprimez une ligne, ce qui rend l'itération non valide.

Cependant, vous pouvez d'abord copier les lignes dans une collection, puis parcourir la collection et supprimer les lignes de cette façon. Cela garantit que l'itération n'est pas interrompue par la modification des données à itérer.

1
Lucero

C’est parce qu’il semble que vous essayez de démonter l’escalier que vous montez. Simplement, vous ne pouvez pas supprimer un élément que vous parcourez.

Par conséquent, vous devez utiliser un tableau différent pour itérer et les supprimer de la propriété datatable Rows.

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

Lorsque les éléments ont une Count, voici ce que j'ai fait:

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

Notez que lorsque les objets ont une collection .GetXXXX(), telle que FileInfo (IIRC), .__, la suppression du contenu de l’élément dans foreach est acceptable. Une solution que j'ai envisagée est la création d'une méthode d'extension qui fournit une méthode .GetItems()

0
IAbstract

Bien sûr Magents

Voici comment je l'ai fait et fonctionne bien

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

Utilisez ceci:

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

{

 myDataTable[i].Delete();

}
0
1111

Cela s'applique à peu près à n'importe quelle collection. Si vous essayez de supprimer un élément en parcourant la collection, vous aurez un problème. Par exemple, si vous supprimez la ligne 3, la ligne précédente 4 devient la ligne 3.

0
DOK