Modifying Collection when using a foreach loop in c# [duplicate]

主宰稳场 提交于 2019-12-09 03:05:56

问题


Basically, I would like to remove an item from a list whilst inside the foreach loop. I know that this is possible when using a for loop, but for other purposes, I would like to know if this is achievable using a foreach loop.

In python we can achieve this by doing the following:

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

for i in a:
    print i

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

This gives the following Output

>>>1
3
4
5
6
7
8
9

But when doing something similar in c#, I get an InvalidOperationException, I was wondering if there was a way of getting around this, without just simply using a for loop.

The code in c# that I used when the exception was thrown:

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

Thanks in advance


回答1:


You can't do this. From the docs for IEnumerator<T>:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.

Alternatives are:

  • Build up a new list of items to remove, then remove them all afterwards
  • Use a normal "for" loop and make sure you're careful about not going over the same element twice or missing any out. (You've said you don't want to do this, but what you're trying to do just won't work.)
  • Build a new collection containing only the elements you want to retain

The last of these alternatives is the LINQ-like solution, where you'd typically write:

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

(Where ShouldBeRetained is whatever logic you want, of course.) The call to ToList() is only necessary if you actually want it in a list. This leads to more declarative code which is often easier to read. I can't easily guess what your original loop is meant to do (it seems pretty odd at the moment) whereas if you can express the logic purely in terms of the item, it can be a lot clearer.




回答2:


If all you need is to remove all items that satisfy a condition you could use the List<T>.RemoveAll method:

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

Note that this modifies the initial list.




回答3:


You definitely may not change a collection in any way when using a foreach loop on it.

You can use a for loop and manage the index for yourself or make a copy of the collection and as you are looping the original, remove items from the copy that equal the item in the original.

In both cases it's not quite as clear or convenient :).



来源:https://stackoverflow.com/questions/1124221/modifying-collection-when-using-a-foreach-loop-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!