Linq - Какой самый быстрый способ узнать отложенное выполнение или нет?
Какой самый быстрый способ выяснить, какие методы linq.net Framework (например,.IEnumerable linq) реализованы с использованием отложенного выполнения, а какие - без отложенного выполнения.
Во время кодирования много раз, мне интересно, будет ли это выполнено правильно. Единственный способ узнать это - перейти к документации MSDN, чтобы убедиться в этом. Будет ли какой-нибудь более быстрый способ, любой каталог, какой-либо список в Интернете, какая-нибудь шпаргалка, любой другой трюк в рукаве, которым вы можете поделиться? Если да, пожалуйста, сделайте это. Это поможет многим linq noobs (таким как я) делать меньше ошибок. Единственный другой вариант - проверять документацию до тех пор, пока один из них не использует их достаточно, чтобы запомнить (что трудно для меня, я не склонен вспоминать "что-нибудь", которое где-то задокументировано и может быть просмотрено:D).
6 ответов
Обычно методы, которые возвращают последовательность, используют отложенное выполнение:
IEnumerable<X> ---> Select ---> IEnumerable<Y>
и методы, которые возвращают единственный объект, не:
IEnumerable<X> ---> First ---> Y
Итак, такие методы, как Where
, Select
, Take
, Skip
, GroupBy
а также OrderBy
использовать отложенное выполнение, потому что они могут, в то время как такие методы, как First
, Single
, ToList
а также ToArray
не потому что они не могут
Есть также два типа отложенного исполнения. Например, Select
метод получает только один элемент за раз, когда его просят произвести элемент, а OrderBy
Метод должен будет использовать весь источник, когда его попросят вернуть первый элемент. Так что, если вы цепочки OrderBy
после Select
выполнение будет отложено до тех пор, пока вы не получите первый элемент, но затем OrderBy
спросит Select
для всех предметов.
Рекомендации, которые я использую:
Всегда предполагайте любой API, который возвращает
IEnumerable<T>
или жеIQueryable<T>
может и, вероятно, будет использовать отложенное выполнение. Если вы используете такой API, и вам нужно перебирать результаты более одного раза (например, чтобы получить счетчик), то перед этим преобразуйте в коллекцию (обычно вызывая метод расширения.ToList ()).Если вы выставляете перечисление, всегда выставляйте его как коллекцию (
ICollection<T>
или жеIList<T>
) если это то, что обычно используют ваши клиенты. Например, уровень доступа к данным часто возвращает коллекцию объектов домена. Только выставитьIEnumerable<T>
если отложенное выполнение является разумным вариантом для представляемого вами API.
На самом деле, это еще не все; Кроме того, вы должны учитывать буферизованные против небуферизованных. OrderBy может быть отложено, но при повторении должен потреблять весь поток.
В общем, все в LINQ, которое возвращает IEnumerable, имеет тенденцию откладываться, в то время как Min и т. Д. (Которые возвращают значения) не откладываются. Буферизация (не против) обычно может быть обоснована, но, честно говоря, рефлектор - довольно быстрый способ узнать наверняка. Но обратите внимание, что часто это все-таки деталь реализации.
См. Классификация стандартных операторов запросов по способу выполнения в MSDN:
https://msdn.microsoft.com/en-us/library/bb882641(v=vs.110).aspx
Для фактического "отложенного выполнения" вам нужны методы, которые работают с 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, часто возвращают класс итератора, который выплевывает объект из его источника всякий раз, когда методы позже в цепочке просят один. Любая операция, которая не требует знания всего набора, может быть лениво оценена (Select и Where - две большие, есть другие). Те, которые требуют знания всей коллекции (сортировка через OrderBy, группирование с GroupBy и агрегаты, такие как Min и Max), будут отбрасывать весь свой перечисляемый источник в List или Array и работать с ним, заставляя вычислять все элементы через все более высокие узлы. Как правило, вы хотите, чтобы они опаздывали в цепочке методов, если вы можете помочь.
Вот краткое описание различных способов узнать, будет ли ваш запрос отложен или нет:
Если вы используете синтаксис выражения запроса вместо синтаксиса метода запроса, то он будет отложен.
Если вы используете синтаксис метода запроса, он МОЖЕТ быть отложен в зависимости от того, что он возвращает.
Наведите курсор на
var
ключевое слово (если это то, что вы используете в качестве типа для переменной, используемой для хранения запроса). Если это говоритIEnumerable<T>
тогда это будет отложено.Попробуйте перебрать запрос, используя foreach. Если вы получаете сообщение о том, что не можете перебрать вашу переменную, потому что она не поддерживает
GetEnumerator()
Вы знаете, запрос не отложен.
Источник: Essential Linq
Если вы приведете коллекцию к IQueryable с помощью.AsQueryable(), ваши вызовы LINQ будут использовать отложенное выполнение.
Смотрите здесь: Использование IQueryable с Linq