Проблема удаления строки в datatable при перечислении - PullRequest
6 голосов
/ 15 декабря 2010

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

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 ]

14 голосов
/ 15 декабря 2010

Вместо использования foreach используйте обратную петлю for:

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

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

3 голосов
/ 15 декабря 2010

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

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

int t_size = table.Rows.Count -1;

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

Редактировать: недостаточно быстро:)

3 голосов
/ 15 декабря 2010

Вы не можете изменить коллекцию внутри foreach вокруг нее.

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

0 голосов
/ 15 декабря 2010

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

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

0 голосов
/ 15 декабря 2010

Кроме того, если вы зависите от порядка обработки строк и обратный цикл не работает для вас. Вы можете добавить строки, которые хотите удалить, в список, а затем после выхода из цикла 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()));
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...