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 operatorssimilares Wheree 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.Whereexecutará o método uma vez para cada pessoa, yieldincluindo 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 IQueryableseja enumerado (implementa IEnumerable<T>, afinal), ele pode combinar vários operadores de consulta (no exemplo acima Wheree FirstOrDefault) para fazer escolhas mais inteligentes sobre como executar toda a consulta nos dados subjacentes fonte (como usar SELECT TOP 1no SQL).
Vejo: