Почему рассчитывается порядок методов LINQ to objects
Я читаю этот вопрос, который объясняет, что порядок методов LINQ для объектов имеет значение. Мой вопрос: почему?
Если я пишу запрос 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, все проекции могут быть размещены в рациональном порядке (например, Order By after Where), как это делает оптимизатор базы данных.
Ответы
Ответ 1
Почему это не работает с LINQ для объектов?
LINQ to Objects не использует деревья выражений. Оператор напрямую преобразуется в ряд вызовов методов, каждый из которых работает как обычный метод С#.
Таким образом, в 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.
Ответ 2
Linq для объектов отложенное выполнение работает иначе, чем linq-to-sql (и EF).
С помощью linq-to-objects цепочка методов будет выполняться в том порядке, в котором перечислены методы: она не использует деревья выражений для хранения и перевода всего объекта.
Вызов OrderBy
, а затем Where
с linq-to-objects будет, когда вы перечисляете результаты, сортируйте коллекцию, , затем отфильтруйте ее. И наоборот, фильтрация результатов с помощью вызова Where
перед его сортировкой с помощью OrderBy
будет, когда вы перечисляете, сначала фильтруете, а затем сортируете. В результате последний случай может иметь огромное значение, поскольку вы потенциально можете сортировать гораздо меньше элементов.
Ответ 3
Поскольку в LINQ для SQL грамматика SQL для SELECT указывает, что различные предложения встречаются в определенной последовательности. Компилятор должен генерировать грамматически правильный SQL.
Применение LINQ для объектов в IEnumerable предполагает итерацию над IEnumerable и применение последовательности действий к каждому объекту в IEnumerable. Вопросы заказа: некоторые действия могут трансформировать объект (или поток самих объектов), другие могут отбрасывать объекты (или вводить новые объекты в поток).
Компилятор не может объяснить ваши намерения. Он создает код, который делает то, что вы сказали сделать в том порядке, в котором вы сказали, чтобы сделать это.
Ответ 4
Совершенно законно использовать побочные операции. Для сравнения:
"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();
Ответ 5
Linq to Objects не переупорядочивает, чтобы избежать потенциального шага выполнения, чтобы сделать что-то, что должно быть оптимизировано во время кодирования. Редакторы мира могут в какой-то момент внедрить инструменты анализа кода, чтобы курить оптимизационные возможности, подобные этому, но это определенно не работа для среды выполнения.