简体   繁体   English

在 LINQ 扩展方法中指定泛型类型的原因

[英]Reasons to specify generic types in LINQ extension methods

Just out of curiosity:只是出于好奇:

Many LINQ extension methods exist as both generic and non-generic variants, for example Any and Any<> , Where and Where<> etc. Writing my queries I usually use the non-generic variants and it works fine.许多 LINQ 扩展方法以通用和非通用变体的形式存在,例如AnyAny<>WhereWhere<>等。编写我的查询时,我通常使用非通用变体,它工作正常。

What would be the cases when one has to use generic methods?什么情况下必须使用泛型方法?

--- edit --- - - 编辑 - -

PS: I am aware of the fact that internally only generic methods are called and the compiler tries to resolve the content of the generic brackets <> during compilation. PS:我知道内部只调用泛型方法并且编译器在编译期间尝试解析泛型括号<>的内容。 My question is rather what are the cases then one has to provide the type explicitly and not to rely on the compiler's intuition?我的问题是什么情况下必须明确提供类型而不依赖于编译器的直觉?

Always.总是。 The C# compiler is smart enough to infer what the type of the method is based on the parameters. C# 编译器足够聪明,可以根据参数推断方法的类型。 This is important when the type is anonymous, and thus has no name.当类型是匿名的,因此没有名称时,这一点很重要。

obj.SomeMethod(123); //these calls are the same
obj.SomeMethod<int>(123);

obj.SomeMethod(new { foo = 123 }); //what type would I write here?!

Edit: To be clear, you are always calling the generic method.编辑:要清楚,您总是在调用泛型方法。 It just looks like a non-generic method, since the compiler and Intellisense are smart.它只是看起来像一个非泛型方法,因为编译器和 Intellisense 很聪明。

Edit: To your updated question, you would want to be specific if you want to use a type that is not the type of the object you are passing.编辑:对于您更新的问题,如果您想使用不是您传递的 object 类型的类型,您需要具体说明。 There are two such cases:有两种这样的情况:

  1. If the parameter implements an interface, and you want to operate on that interface, not the concrete type, then you should specify the interface:如果参数实现了一个接口,并且你想对该接口进行操作,而不是具体类型,那么你应该指定接口:

     obj.DoSomething<IEnumerable<Foo>>( new List<Foo>() );
  2. If the parameter is implicitly convertible to another type, and you want to use the second type, then you should specify it:如果参数可以隐式转换为另一种类型,并且您想使用第二种类型,那么您应该指定它:

     obj.DoSomethingElse<long> ( 123 ); //123 is actually an int, but convertible to long

On the other hand, if you need a cast to do the conversion (or you insert one anyway), then you don't need to specify:另一方面,如果您需要强制转换来进行转换(或者您仍然插入一个),那么您不需要指定:

obj.DoYetAnotherThing( (Transformed)new MyThing() ); // calls DoYetAnotherThing<Transformed>

One example I ran into today:我今天遇到的一个例子:

ObjectSet<User> users = context.Users;
var usersThatMatch = criteria.Aggregate(users, (u, c) => u.Where(c));

The above code won't work because the.Where method doesn't return an ObjectSet<User> .上面的代码不起作用,因为 .Where 方法不返回ObjectSet<User> You could get around this one of two ways.您可以通过以下两种方式之一解决此问题。 I could call .AsQueryable() on users, to make sure it's strongly typed as an IQueryable, or I could pass specific type arguments into the Aggregate method:我可以在用户上调用.AsQueryable() ,以确保它被强类型化为 IQueryable,或者我可以将特定类型 arguments 传递给 Aggregate 方法:

criteria.Aggregate<Func<User, bool>, IEnumerable<User>>(
    PersonSet, (u, c) => u.Where(c));

Another couple of more common examples are the Cast and OfType methods, which have no way to infer what type you want, and in many cases are being called on a non-generic collection in the first place.另外两个更常见的示例是CastOfType方法,它们无法推断出您想要什么类型,并且在许多情况下,首先在非泛型集合上调用。

In general, the folks that designed the LINQ methods went out of their way to avoid the need to use explicit types in these generic methods, and for the most part you don't need to.通常,设计 LINQ 方法的人会竭尽全力避免在这些泛型方法中使用显式类型,而且大多数情况下您不需要。 I'd say it's best to know it's an option, but avoid doing it unless you find it necessary.我会说最好知道这是一种选择,但除非您认为有必要,否则请避免这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM