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

时间:2011-06-29 00:37:02

标签: c# linq generics extension-methods

出于好奇:

许多LINQ扩展方法作为通用和非泛型变体存在,例如AnyAny<>WhereWhere<>等。编写我的查询我经常使用非泛型变体,它工作正常。

当必须使用通用方法时会出现什么情况?

---编辑---

P.S。:我知道内部只调用泛型方法,编译器尝试在编译期间解析通用括号<>的内容。 我的问题是,那么案例是什么,然后必须明确提供类型而不是依赖编译器的直觉?

2 个答案:

答案 0 :(得分:5)

始终。 C#编译器非常智能,可以根据参数推断出方法的类型。当类型是匿名的,因此没有名称时,这很重要。

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

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

编辑:要清楚,您总是调用泛型方法。它看起来像一个非泛型方法,因为编译器和智能感知是聪明的。

编辑:对于您更新的问题,如果您想使用的类型不是您传递的对象的类型,那么您可能希望具体。有两种这样的情况:

  1. 如果参数实现了一个接口,并且你想在该接口上操作,而不是具体类型,那么你应该指定接口:

    obj.DoSomething<IEnumerable<Foo>>( new List<Foo>() );
    
  2. 如果参数可以隐式转换为其他类型,并且您想使用第二种类型,那么您应该指定它:

    obj.DoSomethingElse<long> ( 123 ); //123 is actually an int, but convertible to long
    
  3. 另一方面,如果您需要演员来进行转换(或者您仍然插入一个),那么您需要指定:

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

答案 1 :(得分:3)

我今天遇到的一个例子:

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

上述代码无效,因为.Where方法不会返回ObjectSet<User>。你可以绕过这两种方式中的一种。我可以在用户上调用.AsQueryable(),以确保它被强类型化为IQueryable,或者我可以将特定类型参数传递给Aggregate方法:

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

另外两个更常见的例子是CastOfType方法,它们无法推断出您想要的类型,并且在许多情况下是在非泛型集合中调用第一名。

一般来说,设计LINQ方法的人们不遗余力地避免在这些通用方法中使用显式类型,并且大多数情况下你不需要这样做。我会说最好知道这是一个选项,但除非你认为有必要,否则不要这样做。