c# - Linq: ¿Cuál es la forma más rápida de averiguar la ejecución diferida o no?
.net deferred-execution (6)
¿Cuál es la forma más rápida de descubrir qué métodos de .net framework linq (por ejemplo, los métodos de .IEnumerable linq) se implementan mediante la ejecución diferida frente a los que no se implementan mediante la ejecución diferida?
Mientras codifico muchas veces, me pregunto si este será ejecutado correctamente. La única forma de averiguarlo es ir a la documentación de MSDN para asegurarse. ¿Habría alguna forma más rápida, cualquier directorio, cualquier lista en algún lugar de la web, cualquier hoja de trucos, cualquier otro truco bajo la manga que pueda compartir? Si es así, por favor hágalo. Esto ayudará a muchos linobs (como yo) a cometer menos errores. La única otra opción es verificar la documentación hasta que uno los haya usado lo suficiente como para recordarlos (lo que es difícil para mí, tiendo a no recordar "nada", que está documentado en algún lugar y se puede consultar: D).
Consulte la Clasificación de operadores de consultas estándar por modo de ejecución en MSDN:
https://msdn.microsoft.com/en-us/library/bb882641(v=vs.110).aspx
En realidad, hay más; Además, debe considerar el búfer frente al no búfer. Se puede diferir OrderBy, pero cuando se itera se debe consumir todo el flujo.
En general, cualquier cosa en LINQ que devuelva IEnumerable tiende a diferirse, mientras que Min, etc. (que devuelve valores) no se difiere. El buffering (vs no) generalmente puede ser razonado, pero francamente el reflector es una forma bastante rápida de descubrirlo con seguridad. Pero tenga en cuenta que a menudo este es un detalle de implementación de todos modos.
Generalmente los métodos que devuelven una secuencia usan ejecución diferida:
IEnumerable<X> ---> Select ---> IEnumerable<Y>
y los métodos que devuelven un solo objeto no:
IEnumerable<X> ---> First ---> Y
Por lo tanto, los métodos como Where
, Select
, Take
, Skip
, GroupBy
y OrderBy
utilizan la ejecución diferida porque pueden, mientras que los métodos como First
, Single
, ToList
y ToArray
no lo hacen porque no pueden.
También hay dos tipos de ejecución diferida. Por ejemplo, el método Select
solo obtendrá un elemento a la vez cuando se le OrderBy
que produzca un elemento, mientras que el método OrderBy
tendrá que consumir toda la fuente cuando se le OrderBy
que devuelva el primer elemento. Por lo tanto, si encadena un OrderBy
después de un Select
, la ejecución se aplazará hasta que obtenga el primer artículo, pero luego OrderBy
le pedirá al Select
para todos los artículos.
Las pautas que utilizo:
Siempre asuma que cualquier API que devuelva
IEnumerable<T>
oIQueryable<T>
puede y probablemente usará la ejecución diferida. Si consume una API de este tipo y necesita recorrer los resultados más de una vez (p. Ej., Para obtener un recuento), conviértalo a una colección antes de hacerlo (generalmente, llamando al método de extensión .ToList ()).Si está exponiendo una enumeración, expóngala siempre como una colección (
ICollection<T>
oIList<T>
) si eso es lo que normalmente usarán sus clientes. Por ejemplo, una capa de acceso a datos a menudo devolverá una colección de objetos de dominio. Solo expongaIEnumerable<T>
si la ejecución diferida es una opción razonable para la API que está exponiendo.
Para la "ejecución diferida" real, desea métodos que funcionen en un IQueryable. Las cadenas de métodos se basan en un trabajo de IQueryable para construir un árbol de expresiones que represente su consulta. Solo cuando llama a un método que toma IQueryable y produce un resultado concreto o IEnumerable (ToList () y similar, AsEnumerable (), etc.) el árbol Linq2Objects evalúa el árbol (Linq2Objects está integrado en Framework, como es Linq2SQL y ahora el MSEF; otros ORM y los marcos de capa de persistencia también ofrecen proveedores de Linq) y el resultado real devuelto. Cualquier clase de IEnumerable en el marco puede convertirse en un IQueryable utilizando el método de extensión AsQueryable (), y los proveedores de Linq que traducirán el árbol de expresiones, como ORM, proporcionarán un AsQueryable () como punto de partida para una consulta de linq. sus datos
Incluso contra un IEnumerable, algunos de los métodos de Linq son "perezosos". Debido a que la belleza de un IEnumerable es que no tiene que saberlo todo, solo el elemento actual y si hay otro, los métodos Linq que actúan en un IEnumerable a menudo devuelven una clase de iterador que escupe un objeto desde su origen cada vez que Métodos posteriores en la cadena piden uno. Cualquier operación que no requiera el conocimiento de todo el conjunto puede evaluarse perezosamente (Select y Where son dos grandes; hay otras). Los que requieren conocer la colección completa (la clasificación a través de OrderBy, la agrupación con GroupBy y los agregados como Min y Max) absorberán toda su fuente enumerable en una Lista o Array y trabajarán en ella, forzando la evaluación de todos los elementos a través de todos los nodos superiores. Por lo general, desea que estos lleguen tarde en una cadena de métodos si puede evitarlo.
Si convierte la colección en un IQueryable utilizando .AsQueryable (), sus llamadas LINQ utilizarán la ejecución diferida.
Vea aquí: Usando IQueryable con Linq