Linq - Какой самый быстрый способ узнать отложенное выполнение или нет? - PullRequest
29 голосов
/ 09 октября 2010

Какой самый быстрый способ узнать, какие методы linq .net framework (например, .IEnumerable linq) реализованы с использованием отложенного выполнения, а какие - без отложенного выполнения.

Во время кодирования много раз, мне интересно, будет ли это выполнено правильно.Единственный способ узнать это - перейти к документации MSDN, чтобы убедиться в этом.Будет ли какой-нибудь более быстрый способ, любой каталог, какой-либо список в Интернете, какая-нибудь шпаргалка, любой другой трюк в рукаве, которым вы можете поделиться?Если да, пожалуйста, сделайте это.Это поможет многим linq noobs (таким как я) делать меньше ошибок.Единственный другой вариант - проверять документацию до тех пор, пока один из них не воспользуется ими достаточно, чтобы запомнить (что трудно для меня, я склонен не вспоминать «что-нибудь», которое где-то задокументировано и может быть найдено: D).

Ответы [ 6 ]

36 голосов
/ 09 октября 2010

Обычно методы, которые возвращают последовательность, используют отложенное выполнение:

IEnumerable<X> ---> Select ---> IEnumerable<Y>

, а методы, которые возвращают один объект, не:

IEnumerable<X> ---> First ---> Y

Итак, такие методы, как Where,Select, Take, Skip, GroupBy и OrderBy используют отложенное выполнение, потому что могут, в то время как такие методы, как First, Single, ToList и ToArray, не могут, потому что могут't.

Существует также два типа отложенного выполнения.Например, метод Select будет получать только один элемент за один раз, когда его попросят произвести элемент, в то время как метод OrderBy должен будет потреблять весь источник, когда его попросят вернуть первый элемент.Таким образом, если вы соедините OrderBy после Select, выполнение будет отложено до тех пор, пока вы не получите первый элемент, но затем OrderBy запросит Select для всех элементов.

8 голосов
/ 09 октября 2010

Рекомендации, которые я использую:

  • Всегда предполагайте, что любой API, который возвращает IEnumerable<T> или IQueryable<T>, может и, вероятно, будет использовать отложенное выполнение.Если вы используете такой API и вам нужно перебирать результаты более одного раза (например, чтобы получить счетчик), то перед этим преобразуйте в коллекцию (обычно вызывая метод расширения .ToList ().

  • Если вы предоставляете перечисление, всегда представляйте его как коллекцию (ICollection<T> или IList<T>), если это то, что ваши клиенты обычно используют. Например, слой доступа к данным будетчасто возвращают коллекцию объектов домена. Экспонируйте IEnumerable<T>, только если отложенное выполнение является разумным вариантом для API, который вы предоставляете.

5 голосов
/ 09 октября 2010

На самом деле, есть еще; Кроме того, вы должны рассмотреть буферизованные против небуферизованных. OrderBy может быть отложено, но при повторении должен потреблять весь поток.

В общем, все, что в LINQ возвращает IEnumerable , приводит к отсрочке , в то время как Min и т.д. (которые возвращают значения) не откладываются. Буферизация (не против) обычно может быть обоснована, но, честно говоря, рефлектор - довольно быстрый способ узнать наверняка. Но обратите внимание, что часто это все-таки деталь реализации.

2 голосов
/ 25 января 2019

Вот краткий обзор различных способов узнать, будет ли ваш запрос отложен или нет:

  1. Если вы используете синтаксис выражения запроса вместо синтаксиса метода запроса, то он будет отложен.

  2. Если вы используете синтаксис метода запроса, он МОЖЕТ быть отложен в зависимости от того, что он возвращает.

  3. Наведите курсор на ключевое слово var (если это то, что вы используете в качестве типа переменной, используемой для хранения запроса). Если написано IEnumerable<T>, то оно будет отложено.

  4. Попробуйте перебрать запрос, используя foreach. Если вы получили сообщение об ошибке, в котором говорится, что он не может перебрать вашу переменную, поскольку он не поддерживает GetEnumerator(), вы знаете, что запрос не отложен.

Источник: Essential Linq

2 голосов
/ 09 октября 2010

Для фактического «отложенного выполнения» вам нужны методы, которые работают с IQueryable.Цепочки методов, основанные на IQueryable, работают над созданием дерева выражений, представляющего ваш запрос.Только когда вы вызываете метод, который принимает IQueryable и выдает конкретный или IEnumerable результат (ToList () и аналогичные, AsEnumerable () и т. Д.), Дерево, оцениваемое поставщиком Linq (Linq2Objects, встроено в Framework, как и Linq2SQL итеперь MSEF, другие ORM и платформы уровня постоянства также предлагают провайдеров Linq) и реальный результат возвращается.Любой класс IEnumerable в платформе может быть приведен к IQueryable с использованием метода расширения AsQueryable (), а поставщики Linq, которые будут преобразовывать дерево выражений, например ORM, предоставят AsQueryable () в качестве отправной точки для запроса linq противих данные.

Даже в сравнении с IEnumerable некоторые методы Linq являются «ленивыми».Поскольку прелесть IEnumerable заключается в том, что вам не нужно знать обо всем этом, только о текущем элементе и о наличии другого метода Linq, который работает с IEnumerable, часто возвращают класс итератора, который выплевывает объект из его источника всякий раз, когдаметоды позже в цепочке просят один.Любая операция, которая не требует знания всего набора, может быть лениво оценена (Выбрать и Где две большие, есть другие).Те, которые требуют знания всей коллекции (сортировка через OrderBy, группирование с GroupBy и агрегаты, такие как Min и Max), будут отбрасывать весь свой перечисляемый источник в List или Array и работать с ним, заставляя вычислять все элементы через все более высокие узлы.Как правило, вы хотите, чтобы они запаздывали в цепочке методов, если вы можете помочь.

1 голос
/ 09 октября 2010

Если вы приведете коллекцию к IQueryable с помощью .AsQueryable (), ваши вызовы LINQ будут использовать отложенное выполнение.

См. Здесь: Использование IQueryable с Linq

...