Проблема удаления строки в datatable при перечислении

Я получаю следующую ошибку, когда пытаюсь удалить строку во время цикла через нее.

C#: коллекция была изменена; операция перечисления может не выполняться

Я занимаюсь некоторыми исследованиями некоторое время, и я читал некоторые подобные сообщения здесь, но я все еще не нашел правильный ответ.

foreach (DataTable table in JobsDS.Tables)
{

  foreach (DataRow row in table.Rows)
  {
    if (row["IP"].ToString() != null && row["IP"].ToString() != "cancelled")
    {
        string newWebServiceUrl = "http://" + row["IP"].ToString() + "/mp/Service.asmx";
        webService.Url = newWebServiceUrl;
        string polledMessage = webService.mpMethod(row["IP"].ToString(), row["ID"].ToString());

        if (polledMessage != null)
        {
            if (polledMessage == "stored")
            {               
                removeJob(id);
            }

        }
    }
}

}

любая помощь была бы очень признательна

5 ответов


вместо foreach использовать обратный for петли:

for(int i = table.Rows.Count - 1; i >= 0; i--)
{
    DataRow row = table.Rows[i];
    //do your stuff
}

удаление строки действительно изменяет исходную коллекцию строк. Большинство перечислителей предназначены для взрыва, если они обнаруживают, что исходная последовательность изменилась в середине перечисления, а не пытаются обрабатывать все странные возможности foreaching через что-то, что меняется и, вероятно, ввести очень тонкие ошибки, безопаснее просто запретить его.


вы не можете изменить набор внутри foreach вокруг него.

вместо этого, вы должны использовать обратную for петли.


Если вы хотите удалить элементы из цикла в списке элементов, трюк состоит в том, чтобы использовать цикл for, начать с последнего элемента и перейти к первому элементу.

в вашем примере :

int t_size = table.Rows.Count -1;

for (int i = t_size; i >= 0; i--)
{
   DataRow row = table.Rows[i];
   // your code ...
}

Edit : недостаточно быстро:)


кроме того, если вы зависите от порядка обработки строк, и обратный цикл не работает для вас. Вы можете добавить строки, которые хотите удалить, в список, а затем после выхода из цикла foreach вы можете удалить строки, добавленные в список. Например,

foreach (DataTable table in JobsDS.Tables) 
{ 
  List<DataRow> rowsToRemove = new List<DataRow>();
  foreach (DataRow row in table.Rows) 
  { 
    if (row["IP"].ToString() != null && row["IP"].ToString() != "cancelled") 
    { 
        string newWebServiceUrl = "http://" + row["IP"].ToString() + "/mp/Service.asmx"; 
        webService.Url = newWebServiceUrl; 
        string polledMessage = webService.mpMethod(row["IP"].ToString(), row["ID"].ToString()); 

        if (polledMessage != null) 
        { 
            if (polledMessage == "stored") 
            {                
                //removeJob(id); 
                rowsToRemove.Add(row);
            } 

        } 
    } 
  }
  rowsToRemove.ForEach(r => removeJob(r["ID"].ToString()));
} 

как-то removeJob(id) изменяет один из IEnumerables вашего перечисления (table.Rows или JobsDS.Tables, из названия метода я предполагаю, что это будет последний), возможно, через привязку данных.

Я не уверен, что назад for будет работать напрямую, потому что кажется, что вы удаляете элемент, перечисленный во внешнем foreach изнутри внутреннего foreach. Трудно сказать без дополнительной информации о том, что происходит в removeJob(id).