list.remove()中的偶数异常

本文关键字:异常 remove list | 更新日期: 2023-09-27 18:18:13

我有一个数字列表,我想删除所有偶数。我认为我的代码是正确的:

System.Collections.Generic.List<int> list = ...
foreach (int i in list)
{
  if (i % 2 == 0)
    list.Remove(i);
}

但是当我运行它时,我得到一个异常。我做错了什么?

list.remove()中的偶数异常

你不能在foreach循环中修改集合,也就是说,你不能从list中删除在foreach循环中迭代的项。

代替foreach循环,只使用这一行代码:

list.RemoveAll(i => i % 2 == 0);

不能在foreach循环期间修改集合。foreach循环使用枚举数遍历该集合,当该集合被修改时,枚举数所发生的变化如下:

只要该集合存在,枚举数就保持有效不变。如果对集合进行了更改,例如添加,修改或删除元素时,枚举数不可恢复无效,其行为未定义。

可以使用常规的for循环。

for (int i = 0; i < list.Count; i++)
{
    int n = list[i];
    if (n % 2 == 0)
    {
        list.RemoveAt(i--);
    }
}

foreach在幕后使用IEnumerator,当列表中的元素被删除时,它使枚举器处于潜在的不一致状态。对它来说,最安全的做法是抛出异常。

要解决这个问题,首先创建一个集合的本地副本:

var local = new List<int>(list);
foreach (int i in local) { if (i % 2 == 0) list.Remove(i); }

如果你要从列表中删除任何东西(甚至是数组),你应该向后迭代它,因为删除一个项目会将它之后的所有项目向下移动一个位置。向前迭代将导致每次都跳过下一项。

你得到了哪个异常?有时,foreach会将在foreach中使用的项锁定到无法编辑的位置。相反,使用for(并返回!)

for(int i = list.Length - 1 ; i > -1 ; i--)

遵循@Chris Filstow的方法....

这将获取您的列表,并将其替换为符合条件的新元素:

System.Collections.Generic.List<int> list = ...
list = list.Where( n=> n % 2 == 0 ).ToList();

您可以尝试这样做。(它只创建一个包含偶数的新列表,而不是从现有列表中删除奇数,所以这取决于您想要做什么。)

var numbers = Enumerable.Range(1, 100);
var evens = numbers.Where(n => n % 2 == 1);

所有你得到的foreach循环是readonly,如果你试图改变列表中的项目,它解释了为什么你得到一个异常。这篇文章解释了其中的原因。你可以切换到for循环。

  for  (int i = 1 ; i < list.lenght; i++)
  {
    if (i % 2 == 0)
    list.Remove(i);
  }