Много было сказано ранее, но в корне более технически:
IEnumerable
- это набор объектов в памяти, которые вы можете перечислить - последовательность в памяти, которая позволяет выполнять итерацию (упрощает цикл foreach
, хотя вы может идти только с IEnumerator
). Они хранятся в памяти как есть.
IQueryable
- это дерево выражений , которое в какой-то момент будет переведено во что-то другое со способностью перечислять окончательный результат . Я думаю, это то, что смущает большинство людей.
Они, очевидно, имеют разные значения.
IQueryable
представляет дерево выражений (просто запрос), которое будет преобразовано во что-либо еще базовым поставщиком запросов при вызове API-интерфейсов выпуска, например агрегатных функций LINQ (Sum, Count и т. Д.) Или ToList. [Массив, словарь, ...]. И IQueryable
объекты также реализуют IEnumerable
, IEnumerable<T>
, так что , если они представляют запрос , результат этого запроса может быть повторен. Это означает, что IQueryable не должен быть только запросом. Правильный термин - это деревья выражений .
Теперь, как эти выражения выполняются и к чему они обращаются, зависит от так называемых поставщиков запросов (исполнителей выражений, о которых мы можем думать).
В мире Entity Framework (который является тем мистическим базовым поставщиком источника данных или поставщиком запросов) IQueryable
выражения преобразуются в собственные T-SQL запросы. Nhibernate
делает с ними похожие вещи. Вы можете написать свой собственный, следуя принципам, довольно хорошо описанным в LINQ: например, при создании ссылки IQueryable Provider, и вы можете захотеть иметь пользовательский API запросов для службы поставщика вашего магазина продуктов.
Таким образом, в основном, IQueryable
объекты создаются все время, пока мы явно не освободим их и не попросим систему переписать их в SQL или что-либо еще и отправить цепочку выполнения для дальнейшей обработки.
Как и в случае отложенного выполнения, это функция LINQ
для удержания схемы дерева выражений в памяти и отправки ее в исполнение только по требованию, всякий раз, когда определенные API-интерфейсы вызывается против последовательности (тот же Count, ToList и т. д.).
Правильное использование обоих в значительной степени зависит от задач, стоящих перед вами в конкретном случае. Для хорошо известного шаблона репозитория я лично предпочитаю возвращать IList
, то есть IEnumerable
над списками (индексаторы и тому подобное). Поэтому я советую использовать IQueryable
только в репозиториях и IEnumerable где-либо еще в коде. Не говоря о проблемах с проверяемостью, что IQueryable
разрушает и разрушает принцип разделения интересов . Если вы возвращаете выражение из репозиториев, потребители могут поиграть со слоем персистентности, как они пожелают.
Небольшое дополнение к беспорядку :) (из обсуждения в комментариях))
Ни один из них не является объектами в памяти, поскольку они не являются реальными типами как таковыми, они являются маркерами типа - если вы хотите углубиться в это. Но имеет смысл (и именно поэтому даже MSDN выразил это так) думать о IEnumerables как о коллекциях в памяти, тогда как IQueryables как о деревьях выражений. Дело в том, что интерфейс IQueryable наследует интерфейс IEnumerable, так что, если он представляет запрос, результаты этого запроса могут быть перечислены. Перечисление вызывает выполнение дерева выражений, связанного с объектом IQueryable.
Таким образом, на самом деле вы не можете вызвать любой член IEnumerable, не имея объекта в памяти. В любом случае он попадет туда, если вы это сделаете, если он не пустой. IQueryables - это просто запросы, а не данные.