Почему порядок LINQ для объектов методов имеет значение - PullRequest
10 голосов
/ 21 декабря 2011

Я прочитал ответы на этот вопрос, которые объясняют порядок методов LINQ to objects.У меня вопрос, почему?

Если я пишу запрос LINQ to SQL, не имеет значения порядок методов LINQ - projections, например:

session.Query<Person>().OrderBy(x => x.Id)
                       .Where(x => x.Name == "gdoron")
                       .ToList();

Дерево выраженийбудет преобразован в рациональный SQL, подобный следующему:

  SELECT   * 
  FROM     Persons
  WHERE    Name = 'gdoron'
  ORDER BY Id; 

Когда я запускаю запрос, запрос SQL будет построен в соответствии с деревом выражений, независимо от того, насколько странен порядок методов.
Почему это не так?не работает так же с LINQ to objects?
, когда я перечисляю IQueryable , все проекции могут быть расположены в рациональном порядке (например, Упорядочить по после), как это делает оптимизатор базы данных.

Ответы [ 5 ]

14 голосов
/ 21 декабря 2011

Почему это не работает с LINQ для объектов?

LINQ для объектов не использует деревья выражений.Оператор напрямую превращается в серию вызовов методов, каждый из которых выполняется как обычный метод C #.

Таким образом, в LINQ to Objects следующее:

   var results = collection.OrderBy(x => x.Id)
                   .Where(x => x.Name == "gdoron")
                   .ToList();

Получает превращение впрямые вызовы методов:

   var results = Enumerable.ToList(
                   Enumerable.Where(
                     Enumerable.OrderBy(collection, x => x.Id),
                     x => x.Name = "gdoron"
                   )
                 );

Изучив вызовы методов, вы поймете, почему порядок имеет значение.В этом случае, поместив OrderBy первым, вы фактически вкладываете его в самый внутренний вызов метода.Это означает, что вся коллекция будет заказана, когда будут пересчитаны результаты.Если вы должны были изменить порядок:

   var results = collection
                   .Where(x => x.Name == "gdoron")
                   .OrderBy(x => x.Id)
                   .ToList();

Тогда результирующая цепочка методов переключается на:

   var results = Enumerable.ToList(
                   Enumerable.OrderBy(
                     Enumerable.Where(collection, x => x.Name = "gdoron"),
                     x => x.Id
                   )
                 );

Это, в свою очередь, означает, что сортировать нужно только отфильтрованные результаты.как выполняется OrderBy.

8 голосов
/ 21 декабря 2011

Linq для отложенного выполнения объектов работает иначе, чем linq-to-sql (и EF).

При использовании linq-to-objects цепочка методов будет выполняться в том порядке, в котором перечислены методы - она ​​не использует деревья выражений для хранения и перевода всего этого.

Вызов OrderBy затем Where с linq-to-objects при сортировке результатов отсортирует коллекцию, , а затем отфильтрует ее. И наоборот, фильтрация результатов с вызовом Where до , сортировка с помощью OrderBy, при перечислении сначала фильтрует, а затем сортирует. В результате последний случай может иметь огромное значение, так как вы могли бы отсортировать намного меньше элементов.

4 голосов
/ 21 декабря 2011

Потому что в LINQ для SQL грамматика SQL для SELECT требует, чтобы различные предложения встречались в определенной последовательности.Компилятор должен генерировать грамматически правильный SQL.

Применение LINQ для объектов в IEnumerable включает в себя итерацию по IEnumerable и применение последовательности действий к каждому объекту в IEnumerable.Порядок имеет значение: некоторые действия могут преобразовывать объект (или сам поток объектов), другие могут выбрасывать объекты (или вводить новые объекты в поток).

Компилятор не может угадать ваше намерение.Он создает код, который делает то, что вы сказали, чтобы делать в том порядке, в котором вы сказали это делать.

3 голосов
/ 22 декабря 2011

Совершенно законно использовать побочные действия. Для сравнения:

"crabapple"
    .OrderBy(c => { Console.Write(c); return c; })
    .Where(c => { Console.Write(c); return c > 'c'; })
    .Count();
"crabapple"
    .Where(c => { Console.Write(c); return c > 'c'; })
    .OrderBy(c => { Console.Write(c); return c; })
    .Count();
1 голос
/ 21 декабря 2011

Linq to Objects не переупорядочивает, чтобы избежать потенциального шага во время выполнения, чтобы сделать что-то, что должно быть оптимизировано во время кодирования. В какой-то момент мировые разработчики могут в какой-то момент представить инструменты анализа кода, чтобы выкурить подобные возможности оптимизации, но это определенно не работа для среды выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...