2009-10-13 9 views
2

Dans Linq, les méthodes d'extension telles que Where renvoient une collection IEnumerable, mais les méthodes de tri telles que OrderBy renvoient une collection IOrderedEnumerable.Comment Linq utilise-t-il les méthodes IEnumerable après une méthode IOrderedEnumerable?

Donc, si vous avez une question qui se termine par OrderBy (à savoir retourne un IOrderedEnumerable), vous ne pouvez pas ajouter plus tard une méthode Where - le compilateur se plaint du type étant passé dans Where.

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

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

Cependant, si vous faites tout en une seule requête, c'est bien!

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

Je l'ai regardé l'ensemble réflecteur pour voir si le compilateur a été ré-ordonner l'une des opérations, mais il ne semble pas avoir. Comment cela marche-t-il?

Répondre

8

IOrderedEnumerable<T> étend IEnumerable<T> afin que vous puissiez toujours utiliser l'une des méthodes d'extension. La raison pour laquelle votre premier bloc de code ne fonctionne pas parce que vous avez effectivement écrit:

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

Cela échoue parce que query.Where(...) retourne seulement une IEnumerable<Process>, qui ne peut être attribué à la variable query. Ce n'est pas le Where qui est le problème - c'est l'assignation du résultat à la variable d'origine. Pour démontrer que, ce code fonctionne très 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); 

Vous pouvez déclarer requête à IEnumerable<T> commencer par:

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

// Fine 
query = query.Where(p => p.ProcessName.Length < 5); 
+0

Oui, mais quelle est la différence entre les deux exemples? Pourquoi le second fonctionne-t-il mais le premier ne fonctionne pas? –

+5

Le second n'essaie pas d'affecter une expression 'IEnumerable ' dans une variable de type 'IOrderedEnumerable '. –

Questions connexes