Чтобы понять, почему концепция компиляции не имеет смысла для запросов LINQ to Object, полезно понять, как реализован LINQ. Во-первых, должно быть ясно, что запросы LINQ, написанные в свободном синтаксисе, преобразуются в эквивалентный синтаксис вызова метода в время компиляции компилятором C # независимо от используемого варианта LINQ:
from person in people
where person.Age < 18
select person.Name
// will be converted to:
people.Where(person => person.Age < 18).Select(person => person.Name)
Отныне запрос LINQ в основном представляет собой набор вызовов методов, принимающих некоторые аргументы и обычно преобразующих объект IEnumerable<T>
в другой объект IEnumerable<T>
. Отложенное выполнение, которое отличается от компиляции, просто достигается, если не брать какой-либо объект из исходного IEnumerable<T>
до тех пор, пока вы не пройдете вывод IEnumerable<T>
. По сути, методы с отложенным выполнением работают со своими аргументами символически, не затрагивая исходную коллекцию, создавая генератор, который запрашивает материал как вам угодно.
Имея это в виду, взгляните на лямбда-выражение person => person.Age < 18
в вышеприведенном выражении. Он принимает объект Person
и возвращает bool
. Лямбда-выражения нетипизированы; они могут рассматриваться как деревья выражений или анонимные методы в зависимости от контекста, из которого выводится их тип. В этом случае тип выводится из типа параметра метода расширения Where
. Вот где возникает различие между LINQ to SQL и LINQ to Object. В LINQ to Objects метод Where
просто принимает Func<Person, bool>
, а не Expression<Func<Person, bool>>
. По сути это означает, что в LINQ to Objects компилятор C # компилирует лямбда-выражение до анонимного метода и генерирует IL в время компиляции и передает делегат этому методу в Where
.
В других разновидностях LINQ, таких как LINQ to SQL, лямбда-код не скомпилирован в IL. Вместо этого компилятор создает объект дерева выражений из лямбда-выражения и передает дерево выражения в методы LINQ. Методы LINQ используют эти деревья выражений для построения модели запросов. Когда запрос выполняется, объектная модель, созданная для представления запроса с использованием деревьев выражений, будет преобразована в другую вещь (в зависимости от используемого варианта LINQ), такую как операторы SQL в LINQ to SQL, для выполнения в базе данных. Этот процесс преобразования выполняется во время выполнения, и это то, что мы называем компиляцией запросов LINQ .
Подводя итог, вопрос компилируется в что ? Причина, по которой LINQ to Object не нуждается в компиляции во время выполнения, заключается в том, что он изначально не находится в формате дерева выражений; это уже ил.
Вам почти никогда не нужно беспокоиться о производительности LINQ to Objects по сравнению с обычным циклом.