¿Cómo utiliza LINQ métodos IEnumerable tras un método IOrderedEnumerable?
-
21-09-2019 - |
Pregunta
En Linq, métodos de extensión como Where
volver una colección IEnumerable
, pero los métodos de clasificación como OrderBy
volver una colección IOrderedEnumerable
.
Por lo tanto, si usted tiene una consulta que termina con OrderBy
(es decir, devuelve un IOrderedEnumerable
), no se puede añadir más tarde un método Where
- el compilador se queja sobre el tipo que se pasa en Where
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
query = query.Where(p => p.ProcessName.Length < 5);
Sin embargo, si lo hace todo en una sola consulta, está bien!
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id)
.Where(p => p.ProcessName.Length < 5);
He mirado en el conjunto de reflector para ver si el compilador fue re-ordenar cualquiera de las operaciones, pero no parecen tener. ¿Cómo funciona esto?
Solución
IOrderedEnumerable<T>
extiende IEnumerable<T>
lo que aún puede utilizar cualquiera de los métodos de extensión. La razón de su primer bloque de código no funcionaba se debe a que había escrito con eficacia:
IOrderedEnumerable<Process> query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Fail: can't assign an IEnumerable<Process> into a variable
// of type IOrderedEnumerable<Process>
query = query.Where(p => p.ProcessName.Length < 5);
que falle debido query.Where(...)
sólo devuelve un IEnumerable<Process>
, que no puede ser asignado a la variable query
. No está llamando Where
ese es el problema - es asignar el resultado a la variable original. Para demostrar que, este código funciona muy bien:
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Introduce a new variable instead of trying to reuse the previous one
var query2 = query.Where(p => p.ProcessName.Length < 5);
Como alternativa, se puede declarar consulta que se IEnumerable<T>
a comenzar con:
IEnumerable<Process> query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Fine
query = query.Where(p => p.ProcessName.Length < 5);