Domanda

In LINQ, i metodi di estensione come Where restituiscono una collezione IEnumerable, ma i metodi di ordinamento come OrderBy restituiscono una collezione IOrderedEnumerable.

Quindi, se si dispone di una query che si conclude con OrderBy (cioè restituisce un IOrderedEnumerable), non è possibile in seguito aggiungere un metodo di Where - il compilatore si lamenta il tipo di essere passata in Where

.
var query = Process.GetProcesses()
            .Where(p => p.ProcessName.Length < 10)
            .OrderBy(p => p.Id);

query = query.Where(p => p.ProcessName.Length < 5);

Tuttavia, se lo si fa tutto in una query, va bene!

var query = Process.GetProcesses()
            .Where(p => p.ProcessName.Length < 10)
            .OrderBy(p => p.Id)
            .Where(p => p.ProcessName.Length < 5);

Ho guardato l'assemblea in Reflector per vedere se il compilatore è stato ri-ordinare qualsiasi delle operazioni, ma non sembrano avere. Come funziona?

È stato utile?

Soluzione

IOrderedEnumerable<T> estende IEnumerable<T> in modo da poter ancora utilizzare uno dei metodi di estensione. Il motivo per il vostro primo blocco di codice non ha funzionato è perché si aveva effettivamente scritto:

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);

che non riesce a causa query.Where(...) restituisce solo un IEnumerable<Process>, che non può essere assegnato alla variabile query. Non è chiamando Where che è il problema - è assegnare il risultato di nuovo alla variabile originale. Per dimostrare che, questo codice funziona bene:

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);

In alternativa, è possibile dichiarare query per essere IEnumerable<T> di iniziare 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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top