IEnumerable<T>
представляет курсор только вперед T
. В .NET 3.5 добавлены методы расширения, включающие LINQ standard query operators
, такие как Where
и First
, причем любые операторы, которым требуются предикаты или анонимные функции, принимают Func<T>
.
IQueryable<T>
реализует те же стандартные операторы запросов LINQ, но принимает Expression<Func<T>>
для предикатов и анонимных функций. Expression<T>
- это скомпилированное дерево выражений, разбитая версия метода («наполовину скомпилированный», если хотите), который может быть проанализирован поставщиком запрашиваемого и использован соответствующим образом.
Например:
IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();
IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();
В первом блоке x => x.Age > 18
- это анонимный метод (Func<Person, bool>
), который может быть выполнен как любой другой метод. Enumerable.Where
будет выполнять метод один раз для каждого человека, yield
значений, для которых метод вернул true
.
Во втором блоке x => x.Age > 18
- это дерево выражений (Expression<Func<Person, bool>>
), которое можно рассматривать как «свойство« Возраст »> 18».
Это позволяет существовать таким вещам, как LINQ-to-SQL, поскольку они могут анализировать дерево выражений и преобразовывать его в эквивалентный SQL. А поскольку провайдеру не нужно выполнять до перечисления IQueryable
(в конце концов, он реализует IEnumerable<T>
), он может объединить несколько операторов запросов (в приведенном выше примере Where
и FirstOrDefault
), чтобы сделать их более умными выбор способа выполнения всего запроса к базовому источнику данных (например, использование SELECT TOP 1
в SQL).
См: