2015-10-12 1 views
7

У меня есть IEnumerable<T>, который я хотел отфильтровать на основе предиката LINQ. Я пробовал использовать Where на IEnumerable, как я обычно делаю, но на этот раз я наткнулся на что-то интересное. При вызове «Где» на IEnumerable с предикатом я получаю пустой список в обратном порядке. Я знаю, что он должен создать список с двумя элементами в нем. Если вместо этого я использую FindAll, с тем же предикатом, он затем произведет правильный результат.FindAll Vs Where

Может кто-нибудь объяснить мне, почему это происходит? Я всегда думал, что Where был своего рода ленивой версией FindAll, которая также вернула IEnumerable вместо List. Должно быть больше, чем это? (Я сделал некоторые исследования, но безрезультатно.)

Код:

IEnumerable<View> views = currentProject.Views.Where(
        v => v.Entries.Any(e => e.Type == InputType.IMAGE || e.Type == InputType.VIDEO)); 

IEnumerable<View> views = currentProject.Views.FindAll(
        v => v.Entries.Any(e => e.Type == InputType.IMAGE || e.Type == InputType.VIDEO)); 
+11

'Список .FindAll' возвращает «Список ', тогда как 'Where' возвращает' IEnumerable '. Но 'Where' использует отложенное выполнение, поэтому вы получаете его только тогда, когда вы _materialize_ его, т. Е. с 'ToList'. –

+5

Почему вы не опубликовали это как ответ? :) Лучшее объяснение, чем единственный ответ здесь, который был опубликован позже вашего комментария. –

+0

Несмотря на то, что ваш комментарий ответил на вопрос, был отправлен ответ, который отвечает на него более подробно, чем любой из ответов на связанный вопрос. –

ответ

1

Вы можете найти ответ на свой вопрос здесь: LINQ, Where() vs FindAll(). В основном, если вы вызываете .ToList() на вашем «Где», они будут одинаковыми.

Вы можете узнать больше о различиях между отсроченным и немедленным исполнением: https://code.msdn.microsoft.com/LINQ-Query-Execution-ce0d3b95

+0

Я знаю, что то, что вы заявляете, вероятно, является упрощенным объяснением различий между ними, но я понимаю.Благодаря! –

2

Моим предположением было бы что-то происходит между вызовом Где, который создает перечислитель и место в коде, где фактически используется результаты (т. е. где MoveNext и (get_) Ток этого перечислителя фактически вызывается, например, из ToList).

+0

Проблема заключалась в том, что я не вызывал .ToList() при использовании Where() в IEnumerable, поэтому проверка этого показала пустой список. –

1

Да, где находится ленивая версия findall. FindAll() является функцией типа List, это не метод расширения LINQ, например Where. Метод FindAll в List, который является методом экземпляра, который возвращает новый List с тем же типом элемента. FindAll можно использовать только в экземплярах List, тогда как методы расширения LINQ работают на любом типе, который реализует IEnumerable.

Основное отличие (помимо того, что они реализованы на: IEnumerable vs. List), заключается в том, что Where реализует отложенное выполнение, где оно фактически не выполняет поиск до его нужного значения (используя его в цикле foreach для пример). FindAll - это метод немедленного выполнения.

Я буду ссылаться на структуру данных, называемую деревом выражений, чтобы понимать отложенное выполнение, вам нужно только понять, что дерево выражений представляет собой структуру данных, такую ​​как список или очередь. Он содержит запрос LINQ to SQL не результаты запроса, а фактические элементы самого запроса.

Чтобы понять Where Working мы должны видеть, что если написать код

var query = from customer in db.Customers 
     where customer.City == "Paris" 
     select customer;    

Запрос не выполняется здесь в то время как это выполнить в цикле Еогеасп

Чтобы понять LINQ and Deferred Execution