如何有条件地从 .NET 集合中删除项目

2024-03-03

我正在尝试在 .NET 中编写一个扩展方法,它将对通用集合进行操作,并从集合中删除与给定条件匹配的所有项目。

这是我的第一次尝试:

public static void RemoveWhere<T>(this ICollection<T> Coll, Func<T, bool> Criteria){
    foreach (T obj in Coll.Where(Criteria))
        Coll.Remove(obj);
}

但是,这会引发 InvalidOperationException,“集合已修改;枚举操作可能无法执行”。这确实有道理,所以我第二次尝试使用第二个集合变量来保存需要删除的项目并对其进行迭代:

public static void RemoveWhere<T>(this ICollection<T> Coll, Func<T, bool> Criteria){
    List<T> forRemoval = Coll.Where(Criteria).ToList();

    foreach (T obj in forRemoval)
        Coll.Remove(obj);
}

这会引发相同的异常;我不确定我是否真的理解为什么“Coll”不再是被迭代的集合,那么为什么它不能被修改呢?

如果有人对我如何让它发挥作用有任何建议,或者有更好的方法来实现这一目标,那就太好了。

Thanks.


For List<T>,这已经存在,因为RemoveAll(Predicate<T>)。因此,我建议您保留该名称(允许熟悉和优先)。

基本上,迭代时无法删除。有两种常见的选择:

  • 使用基于索引器的迭代(for)和移除
  • 缓冲要删除的项目,并在之后删除foreach(正如你已经做过的那样)

所以也许:

public static void RemoveAll<T>(this IList<T> list, Func<T, bool> predicate) {
    for (int i = 0; i < list.Count; i++) {
        if (predicate(list[i])) {
            list.RemoveAt(i--);
        }
    }
}

或者更一般地对于任何ICollection<T>:

public static void RemoveAll<T>(this ICollection<T> collection, Func<T, bool> predicate) {
    T element;

    for (int i = 0; i < collection.Count; i++) {
        element = collection.ElementAt(i);
        if (predicate(element)) {
            collection.Remove(element);
            i--;
        }
    }
}

这种方法的优点是可以避免列表的大量额外副本。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何有条件地从 .NET 集合中删除项目 的相关文章

随机推荐