在使用C#中的foreach循环时修改集合

8

基本上,我想在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个回答

26
你无法这样做。根据 IEnumerator<T> 的文档:
枚举器只要集合保持不变就有效。如果对集合进行更改,比如添加、修改或删除元素,则枚举器将被不可恢复地使无效,其行为是未定义的。
解决方案有:
- 构建一个新的要移除的项目列表,然后一次性删除它们。 - 使用普通的“for”循环,并确保不重复遍历相同的元素或漏掉任何元素。(你说你不想这样做,但你试图做的事情是行不通的。) - 构建一个仅包含您想要保留的元素的新集合。
最后一种替代方法是类似于 LINQ 的解决方案,你通常会编写:
var newList = oldList.Where(x => ShouldBeRetained(x)).ToList();

(其中ShouldBeRetained是任何你想要的逻辑。)对于实际上需要在列表中使用的情况,调用ToList()是必要的。这将导致更多声明性的代码,通常更容易阅读。我很难猜测您原始的循环意图(目前看起来相当奇怪),而如果您可以纯粹地按照项目表达逻辑,那么它会变得更加清晰。


我主要是想知道在 foreach 实例中是否有什么地方我错过了什么,但如果无法实现,至少现在已经确认了!感谢您的回答。 - Lloyd Powell

6
如果您只需要删除所有满足特定条件的项,可以使用 List<T>.RemoveAll 方法:
List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
MyList.RemoveAll(item => item == "1");

请注意,这将修改初始列表。

1

在使用foreach循环时,绝对不能以任何方式更改集合。

您可以使用for循环并自行管理索引,或者复制集合并在循环原始集合时从副本中删除与原始集合中相等的项。

在这两种情况下,都不太清晰或方便 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接