Как Linq использует методы IEnumerable после метода IOrderedEnumerable?
В Linq такие методы расширения, как Where
вернуть IEnumerable
коллекция, но методы сортировки, такие как OrderBy
вернуть IOrderedEnumerable
коллекция.
Итак, если у вас есть запрос, который заканчивается OrderBy
(т.е. возвращает IOrderedEnumerable
), вы не можете позже добавить Where
метод - компилятор жалуется на тип, передаваемый в Where
,
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
query = query.Where(p => p.ProcessName.Length < 5);
Однако, если вы делаете все это в одном запросе, это нормально!
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id)
.Where(p => p.ProcessName.Length < 5);
Я посмотрел на сборку в Reflector, чтобы увидеть, перекомпилировал ли компилятор какую-либо из операций, но, похоже, этого не произошло. Как это работает?
1 ответ
IOrderedEnumerable<T>
продолжается IEnumerable<T>
так что вы все равно можете использовать любой из методов расширения. Причина, по которой ваш первый блок кода не работал, заключается в том, что вы эффективно написали:
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);
Это не удается, потому что query.Where(...)
только возвращает IEnumerable<Process>
, который не может быть назначен на query
переменная. Это не звонит Where
в этом проблема - это присвоение результата обратно исходной переменной. Чтобы продемонстрировать это, этот код будет отлично работать:
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);
Кроме того, вы можете объявить запрос IEnumerable<T>
начать с:
IEnumerable<Process> query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Fine
query = query.Where(p => p.ProcessName.Length < 5);