IEnumerable<T>
representa um cursor somente para frente de T
. O .NET 3.5 adicionou métodos de extensão que incluíam LINQ standard query operators
similares Where
e First
, com qualquer operador que exija predicados ou funções anônimas Func<T>
.
IQueryable<T>
implementa os mesmos operadores de consulta padrão do LINQ, mas aceita Expression<Func<T>>
para predicados e funções anônimas. Expression<T>
é uma árvore de expressão compilada, uma versão fragmentada do método ("semi-compilado", se você desejar) que pode ser analisado pelo provedor da consulta e usado de acordo.
Por exemplo:
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();
No primeiro bloco, x => x.Age > 18
é um método anônimo ( Func<Person, bool>
), que pode ser executado como qualquer outro método. Enumerable.Where
executará o método uma vez para cada pessoa, yield
incluindo valores para os quais o método retornou true
.
No segundo bloco, x => x.Age > 18
é uma árvore de expressão ( Expression<Func<Person, bool>>
), que pode ser considerada como "é a propriedade 'Age'> 18".
Isso permite que coisas como LINQ-to-SQL existam porque elas podem analisar a árvore de expressão e convertê-la em SQL equivalente. E como o provedor não precisa executar até que IQueryable
seja enumerado (implementa IEnumerable<T>
, afinal), ele pode combinar vários operadores de consulta (no exemplo acima Where
e FirstOrDefault
) para fazer escolhas mais inteligentes sobre como executar toda a consulta nos dados subjacentes fonte (como usar SELECT TOP 1
no SQL).
Vejo: