Строго типизированные методы расширения LINQ - PullRequest
1 голос
/ 16 ноября 2011

Я заметил, что все методы расширения Linq Where, Any, Take и т. Д. Все возвращают IEnumerable.Для моего приложения было бы намного лучше, если бы они возвращали экземпляр того же типа, что и тот, к которому я обращаюсь.

Так, например, если я вызову myList.Where(...) на LinkedList, я быхотел бы получить LinkedList назад, на List я хотел бы List назад и т. д.

Это становится более раздражающим, когда у меня есть такой тип как

class MyType
{
    public string MyField;
}

class MyCollection : List<MyType>
{
    // Some useful stuff in here
}

в этом случае я хотел бы иметь возможность сделать

MyCollection source = .......
MyCollection filtered = source.Where(obj => obj.MyField != null);

К сожалению, это не будет работать из коробки.Тем не менее, я подошел ближе, используя следующий код

public static ListType Filtered<ListType, ElementType>(this ListType @this, Predicate<ElementType> filter) where ListType : class, ICollection<ElementType>, new()
{
    // Arguments checks omitted

    // Create return instance
    var filtered = new ListType();

    // Apply filter for each element
    foreach (var item in @this)
    {
        if (filter(item))
            filtered.Add(item);
    }

    return filtered;
}

, который я могу сделать (обратите внимание на строго типизированный делегат)

MyCollection source = .......
MyCollection filtered = source.Filtered((MyType obj) => obj.MyField != null);

Поэтому мой вопрос: зачем мне второйуниверсальный аргумент в Filter<ListType, ElementType>, когда я указываю where ListType : ICollection<ElementType>?Я понимаю, что не могу использовать в where универсальные типы, которые я не добавил в объявление метода, но почему это так?Есть ли лучший способ сделать это, что я упустил из виду?

1 Ответ

3 голосов
/ 16 ноября 2011

Ну, вам нужны два типа параметров, потому что у вас есть два типа: тип коллекции и тип элемента. Нельзя сказать, что нужно реализовать IFoo<T> для какого-то вида T, но нам все равно, что это за T.

Вы также , используя оба типа в другом месте в объявлении: ListType в качестве возвращаемого типа и ElementType в объявлении предиката. (Это объявление метода было бы легче понять, если бы вы следовали соглашениям об именах .NET и называли их, например, как TCollection и TElement.)

Вы также , используя оба типа в теле метода: item статически типизировано как ElementType, а filtered статически типизировано как ListType.

Трудно понять, как бы вы выразили все это без обоих параметров типа. Учитывая, что вывод типа позволяет вызывать метод без явного указания, мне не ясно, почему это проблема ...

...