我注意到所有Linq扩展方法Where
,Any
,Take
等都返回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
中使用我没有添加到方法声明中的任何泛型类型,但为什么会这样?有没有更好的办法让我忽略了?
答案 0 :(得分:3)
嗯,您需要两个类型参数,因为您涉及两种类型:集合类型和元素类型。没有办法说,它必须为某些类IFoo<T>
实现T
,但我们不关心T
是什么。
你也使用声明中其他类型的两种类型:ListType
作为返回类型,并在谓词声明中使用ElementType
。 (顺便提一下,如果您遵循.NET命名约定并将其称为TCollection
和TElement
,则此方法声明将更容易理解。)
你也在方法体中使用这两种类型:item
被静态输入为ElementType
,而filtered
被静态输入为{ {1}}。
很难看出如何在没有两种类型参数的情况下表达所有。鉴于类型推断允许你调用方法而不是明确的,我不清楚为什么这是一个问题......