强类型LINQ扩展方法

时间:2011-11-16 15:29:54

标签: c# linq generics collections

我注意到所有Linq扩展方法WhereAnyTake等都返回IEnumerable。对于我的应用程序,如果它们返回的是与我呼叫的实例类型相同的实例,那将会更好。

例如,如果我在myList.Where(...)上呼叫LinkedList,我希望LinkedList返回List我想要List 1}}回来等等。

当我有类似

的类型时,这会变得更烦人
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 个答案:

答案 0 :(得分:3)

嗯,您需要两个类型参数,因为您涉及两种类型:集合类型和元素类型。没有办法说,它必须为某些IFoo<T>实现T,但我们不关心T是什么。

使用声明中其他类型的两种类型:ListType作为返回类型,并在谓词声明中使用ElementType。 (顺便提一下,如果您遵循.NET命名约定并将其称为TCollectionTElement,则此方法声明将更容易理解。)

在方法体中使用这两种类型:item被静态输入为ElementType,而filtered被静态输入为{ {1}}。

很难看出如何在没有两种类型参数的情况下表达所有。鉴于类型推断允许你调用方法而不是明确的,我不清楚为什么这是一个问题......