Как создать метод расширения для обработки bindinglist.removeall с предикатом ввода - PullRequest
2 голосов
/ 06 июля 2011
myGenericList.RemoveAll(x => (x.StudentName == "bad student"));

Отлично работает, но в списке привязок этот метод отсутствует.Как я могу создать метод расширения для списка привязок, который принимает в качестве входных данных предикат и выполняет магию, как консервированное удаление всех для List

thankyou

Ответы [ 2 ]

5 голосов
/ 06 июля 2011

Как я уже сказал в комментарии, в методах расширения нет магии, просто напишите код так же, как если бы вы написали его нормально, просто поместите его в статический метод в статическом классе и используйте ключевое слово 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 (N 2 )), потому что каждый 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 (N 2 ), потому что каждый RemoveAt() должен перемещать все элементы после того, который был удален.

1 голос
/ 06 июля 2011

Я бы сказал:

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 ()?

...