Изменение коллекции при использовании цикла foreach в c# [дубликат]

этот вопрос уже есть ответ здесь:

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

в python мы можем достичь этого, выполнив следующее:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

for i in a:
    print i

    if i == 1:
        a.pop(1)

Это дает следующий результат

>>>1
3
4
5
6
7
8
9

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

код в C#, который я использовал, когда было создано исключение:

static void Main(string[] args)
  {
  List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9"});

  foreach (string Item in MyList)
    {
    if (MyList.IndexOf(Item) == 0)
      {
      MyList.RemoveAt(1);
      }

    Console.WriteLine(Item);
    }
  }

спасибо заранее

3 ответов


вы не можете этого сделать. Из документов для IEnumerator<T>:

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

варианты:

  • создайте новый список элементов для удаления, а затем удалите их все потом! .. --16-->
  • используйте обычный цикл" для " и убедитесь, что вы осторожны, не переходя через один и тот же элемент дважды или не хватает. (Вы сказали, что не хотите этого делать, но то, что вы пытаетесь сделать, просто не сработает.)
  • создайте новую коллекцию, содержащую только элементы, которые вы хотите сохранить

последней из этих альтернатив является LINQ-подобное решение, где вы обычно пишете:

var newList = oldList.Where(x => ShouldBeRetained(x)).ToList();

(где ShouldBeRetained - это все логика ты, конечно, хочешь.) Вызов ToList() необходимо только если вы действительно хотите, чтобы он был в списке. Это приводит к более декларативному коду, который часто легче читать. Я не могу легко догадаться, что должен делать ваш исходный цикл (на данный момент это кажется довольно странным), тогда как если вы можете выразить логику исключительно в терминах элемента, это может быть намного яснее.


Если все, что вам нужно, это удалить все элементы, которые удовлетворяют условию, вы можете использовать Список.Метод removeall способ:

List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
MyList.RemoveAll(item => item == "1");

обратите внимание, что это изменяет первоначальный список.


вы определенно не можете изменить коллекцию каким-либо образом при использовании цикла foreach на нем.

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

в обоих случаях это не совсем так, как понятно и удобно :).