迭代列表时从列表中删除元素时出现问题

时间:2010-08-23 08:13:02

标签: c# loops foreach

我有一个遍历列表中元素的循环。我需要根据某些条件从循环中删除此列表中的元素。当我尝试在C#中执行此操作时,我得到一个例外。显然,不允许从列表中删除正在迭代的元素。使用foreach循环观察到该问题。有没有什么标准方法可以解决这个问题?

注意:我能想到的一个解决方案是仅为迭代目的创建列表副本,并从循环内的原始列表中删除元素。我正在寻找一种更好的解决方法。

8 个答案:

答案 0 :(得分:16)

使用List<T>ToArray()方法在这种情况下有很大帮助:

List<MyClass> items = new List<MyClass>();
foreach (MyClass item in items.ToArray())
{
    if (/* condition */) items.Remove(item);
}

替代方法是使用for循环而不是foreach,但是每当删除元素时,你必须减少索引变量,即

List<MyClass> items = new List<MyClass>();
for (int i = 0; i < items.Count; i++)
{
    if (/* condition */)
    {
        items.RemoveAt(i);
        i--;
    }
}

答案 1 :(得分:13)

如果您的列表是实际的List<T>,那么您可以使用内置的RemoveAll方法根据谓词删除项目:

int numberOfItemsRemoved = yourList.RemoveAll(x => ShouldThisItemBeDeleted(x));

答案 2 :(得分:5)

您可以使用整数索引删除项目:

List<int> xs = new List<int> { 1, 2, 3, 4 };
for (int i = 0; i < xs.Count; ++i)
{
    // Remove even numbers.
    if (xs[i] % 2 == 0)
    {
        xs.RemoveAt(i);
        --i;
    }
}

这可能很难阅读并且难以维护,特别是如果循环中的逻辑变得更复杂。

答案 3 :(得分:4)

您可以使用LINQ通过过滤掉项目来将新列表替换为初始列表:

IEnumerable<Foo> initialList = FetchList();
initialList = initialList.Where(x => SomeFilteringConditionOnElement(x));
// Now initialList will be filtered according to the condition
// The filtered elements will be subject to garbage collection

这样您就不必担心循环了。

答案 4 :(得分:2)

另一个技巧是向后循环遍历列表。删除项目不会影响在循环的其余部分中遇到的任何项目。

我不推荐这个或其他任何东西。您需要的所有内容都可以使用LINQ语句来过滤您的要求列表。

答案 5 :(得分:1)

建议的解决方案是将您要删除的所有元素放在一个单独的列表中,在第一个循环之后,放置第二个循环,迭代删除列表并从第一个列表中删除这些元素。

答案 6 :(得分:1)

你可以这样用foreach迭代:

List<Customer> custList = Customer.Populate();

foreach (var cust in custList.ToList())

{

        custList.Remove(cust);

}

注意:在变量列表上的ToList,它会遍历ToList创建的列表,但会从原始列表中删除项目。

希望这有帮助。

答案 7 :(得分:0)

您收到错误的原因是因为您正在使用foreach循环。如果你考虑foreach循环如何工作,这是有道理的。 foreach循环调用List上的GetEnumerator方法。如果您在哪里更改List中的元素数,则foreach循环保持的Enumerator将没有正确数量的元素。如果删除了一个元素,则会抛出null异常错误,如果添加了一个元素,则循环将丢失一个项目。

如果您喜欢Linq和Lamda的表达方式,我会推荐Darin Dimitrov解决方案,否则我会使用Chris Schmich提供的解决方案。