我正在尝试在 .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”不再是正在迭代的集合,所以为什么不能修改它?
如果有人对我如何实现它有任何建议,或者有更好的方法来实现同样的效果,那就太好了。
谢谢。
最佳答案
对于 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--;
}
}
}
这种方法的优点是避免了列表的大量额外副本。
关于c# - 如何有条件地从 .NET 集合中删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/653596/