Причины для указания универсальных типов в методах расширения 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 умны.
Изменить: К вашему обновленному вопросу, вы хотели бы быть конкретным, если вы хотите использовать тип, который не является типом объекта, который вы передаете. Есть два таких случая:
Если параметр реализует интерфейс, и вы хотите работать с этим интерфейсом, а не с конкретным типом, то вы должны указать интерфейс:
obj.DoSomething<IEnumerable<Foo>>( new List<Foo>() );
Если параметр неявно конвертируется в другой тип, и вы хотите использовать второй тип, вам следует указать его:
obj.DoSomethingElse<long> ( 123 ); //123 is actually an int, but convertible to long
С другой стороны, если вам нужен приведение для выполнения преобразования (или вы в любом случае вставляете приведение), вам не нужно указывать:
obj.DoYetAnotherThing( (Transformed)new MyThing() ); // calls DoYetAnotherThing<Transformed>