如何创建一个扩展方法来处理带有谓词输入的bindinglist.removeall
本文关键字:处理 谓词 输入 bindinglist removeall 扩展 创建 何创建 一个 方法 | 更新日期: 2023-09-27 18:01:15
myGenericList.RemoveAll(x => (x.StudentName == "bad student"));
效果很好,但是绑定列表没有这个方法。我如何为bindinglist创建一个扩展方法,该方法将谓词作为输入,并像List的罐装removeall一样神奇
感谢
正如我在评论中所说,扩展方法没有魔力,只需像正常编写一样编写代码,只需将其放入静态类中的静态方法中,并使用this
关键字:
public static void RemoveAll<T>(this BindingList<T> list, Func<T, bool> predicate)
{
foreach (var item in list.Where(predicate).ToArray())
list.Remove(item);
}
您必须使用ToArray()
(或ToList()
(,因为Where()
是惰性的,只在需要时枚举集合,而不能枚举正在更改的集合。
尽管这个解决方案相当慢(O(N2((,因为每个Remove()
都必须查看集合才能找到要删除的正确项目。我们可以做得更好:
public static void FastRemoveAll<T>(this BindingList<T> list, Func<T, bool> predicate)
{
for (int i = list.Count - 1; i >= 0; i--)
if (predicate(list[i]))
list.RemoveAt(i);
}
这使用了这样一个事实,即我们可以在恒定时间内到达第i个项目,因此整个方法是O(N(。迭代更容易向后写,因此我们尚未考虑的项的索引不会发生变化。
编辑:实际上,第二个解决方案仍然是O(N2(,因为每个RemoveAt()
都必须移动被删除的项目之后的所有项目。
我想说:
public static class BindingListExtensions
{
public static void RemoveAll<T>(this BindingList<T> list, Func<T, bool> predicate)
{
// first check predicates -- uses System.Linq
// could collapse into the foreach, but still must use
// ToList() or ToArray() to avoid deferred execution
var toRemove = list.Where(predicate).ToList();
// then loop and remove after
foreach (var item in toRemove)
{
list.Remove(item);
}
}
}
对于那些对细节感兴趣的人来说,ToList((和ToArray((的性能似乎非常接近(事实上,根据具体情况,两者都可以更快(,以至于可以忽略不计:我需要迭代和计数。什么是最快的或首选的:ToArray((或ToList((?