Mucho se ha dicho anteriormente, pero volviendo a las raíces, de una manera más técnica:
IEnumerable es una colección de objetos en memoria que puede enumerar , una secuencia en memoria que permite iterar (facilita el foreachbucle interno , aunque IEnumeratorsolo puede hacerlo ). Residen en la memoria como es.
IQueryable es un árbol de expresión que se traducirá a otra cosa en algún momento con capacidad de enumerar sobre el resultado final . Supongo que esto es lo que confunde a la mayoría de las personas.
Obviamente tienen diferentes connotaciones.
IQueryablerepresenta un árbol de expresión (una consulta, simplemente) que el proveedor de consultas subyacente traducirá a otra cosa tan pronto como se invoquen las API de lanzamiento, como las funciones agregadas de LINQ (Sum, Count, etc.) o ToList [Array, Dictionary ,. ..]. Y los IQueryableobjetos también se implementan IEnumerable, de IEnumerable<T>modo que si representan una consulta, el resultado de esa consulta podría iterarse. Significa que IQueryable no tiene que ser solo consultas. El término correcto es que son árboles de expresión .
Ahora, cómo se ejecutan esas expresiones y a qué recurren todo depende de los llamados proveedores de consultas (ejecutores de expresiones en los que podemos pensar).
En el mundo de Entity Framework (que es ese proveedor de fuente de datos subyacente místico, o el proveedor de consultas), las IQueryableexpresiones se traducen en consultas T-SQL nativas . Nhibernatehace cosas similares con ellos. Puede escribir el suyo siguiendo los conceptos bastante bien descritos en LINQ: por ejemplo, crear un enlace de proveedor IQueryable , y es posible que desee tener una API de consulta personalizada para su servicio de proveedor de tienda de productos.
Básicamente, los IQueryableobjetos se construyen todo el tiempo hasta que los liberamos explícitamente y le decimos al sistema que los reescriba en SQL o lo que sea y envíe la cadena de ejecución para su procesamiento posterior.
Como si se tratara de una ejecución diferida , es una LINQcaracterística mantener el esquema del árbol de expresión en la memoria y enviarlo a la ejecución solo a pedido, siempre que se invoquen ciertas API contra la secuencia (el mismo Count, ToList, etc.).
El uso adecuado de ambos depende en gran medida de las tareas que enfrenta para el caso específico. Para el conocido patrón de repositorio, personalmente opto por volver IList, eso es IEnumerablesobre Listas (indexadores y similares). Por lo tanto, es mi consejo usar IQueryablesolo dentro de repositorios e IEnumerable en cualquier otro lugar del código. No decir sobre las preocupaciones de comprobabilidad que IQueryablerompe y arruina el principio de separación de preocupaciones . Si devuelve una expresión desde dentro de los repositorios, los consumidores pueden jugar con la capa de persistencia como desearían.
Una pequeña adición al desorden :) (de una discusión en los comentarios)) Ninguno de ellos son objetos en la memoria ya que no son tipos reales per se, son marcadores de un tipo, si quieres profundizar tanto. Pero tiene sentido (y es por eso que incluso MSDN lo expresó de esta manera) pensar en IEnumerables como colecciones en memoria, mientras que IQueryables como árboles de expresión. El punto es que la interfaz IQueryable hereda la interfaz IEnumerable de modo que si representa una consulta, los resultados de esa consulta se pueden enumerar. La enumeración hace que se ejecute el árbol de expresión asociado con un objeto IQueryable. Entonces, de hecho, no se puede llamar a ningún miembro IEnumerable sin tener el objeto en la memoria. Entrará allí si lo hace, de todos modos, si no está vacío. IQueryables son solo consultas, no los datos.