Причины для указания универсальных типов в методах расширения LINQ

Просто из любопытства:

Многие методы расширения LINQ существуют как общие, так и неуниверсальные варианты, например Any а также Any<>, Where а также Where<> и т. д. При написании своих запросов я обычно использую неуниверсальные варианты, и это прекрасно работает.

Какие бывают случаи, когда нужно использовать универсальные методы?

--- редактировать ---

PS: я знаю о том, что внутренне вызываются только общие методы, и компилятор пытается разрешить содержимое общих скобок <> во время компиляции. Мой вопрос, скорее, в каких случаях нужно явно указывать тип, а не полагаться на интуицию компилятора?

2 ответа

Решение

Один пример, с которым я столкнулся сегодня:

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));

Другая пара более распространенных примеров - это Cast а также OfType методы, которые не могут определить, какой тип вам нужен, и во многих случаях в первую очередь вызываются для неуниверсальной коллекции.

В общем, люди, которые разрабатывали методы LINQ, старались изо всех сил избегать необходимости использовать явные типы в этих универсальных методах, и по большей части вам это не нужно. Я бы сказал, что лучше знать, что это вариант, но избегайте этого, если не считаете это необходимым.

Всегда. Компилятор C# достаточно умен, чтобы определить, какой тип метода основан на параметрах. Это важно, когда тип является анонимным и поэтому не имеет имени.

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

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

Изменить: Чтобы было ясно, вы всегда вызываете универсальный метод. Это выглядит как неуниверсальный метод, так как компилятор и Intellisense умны.

Изменить: К вашему обновленному вопросу, вы хотели бы быть конкретным, если вы хотите использовать тип, который не является типом объекта, который вы передаете. Есть два таких случая:

  1. Если параметр реализует интерфейс, и вы хотите работать с этим интерфейсом, а не с конкретным типом, то вы должны указать интерфейс:

    obj.DoSomething<IEnumerable<Foo>>( new List<Foo>() );
    
  2. Если параметр неявно конвертируется в другой тип, и вы хотите использовать второй тип, вам следует указать его:

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

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

obj.DoYetAnotherThing( (Transformed)new MyThing() ); // calls DoYetAnotherThing<Transformed>
Другие вопросы по тегам