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 foreach
bucle interno , aunque IEnumerator
solo 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.
IQueryable
representa 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 IQueryable
objetos 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 IQueryable
expresiones se traducen en consultas T-SQL nativas . Nhibernate
hace 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 IQueryable
objetos 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 LINQ
caracterí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 IEnumerable
sobre Listas (indexadores y similares). Por lo tanto, es mi consejo usar IQueryable
solo dentro de repositorios e IEnumerable en cualquier otro lugar del código. No decir sobre las preocupaciones de comprobabilidad que IQueryable
rompe 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.