Деревья выражений в поставщиках LINQ
Узнайте, как поставщики преобразуют выражения в запросы.
«Деревья выражений в поставщиках LINQ» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Зачем LINQ нужны деревья выражений
У LINQ есть два варианта. IEnumerable<T> выполняет лямбды в памяти. IQueryable<T> получает их как деревья выражений, чтобы провайдер мог преобразовать их в другой язык, например SQL.
IEnumerable и IQueryable
Разница заключается в типе параметра: IEnumerable.Where принимает Func<T,bool> (скомпилированный код), а IQueryable.Where принимает Expression<Func<T,bool>> (дерево).
using System;
using System.Linq;
using System.Linq.Expressions;
int[] nums = { 1, 2, 3, 4 };
// IEnumerable path: lambda is a compiled delegate
var evens = nums.Where(n => n % 2 == 0);
Console.WriteLine(string.Join(",", evens)); // 2,4Запрос остаётся данными
При использовании IQueryable Ваша лямбда сохраняется как дерево выражений и пока не выполняется. Провайдер проверяет дерево, чтобы построить запрос.
using System;
using System.Linq;
using System.Linq.Expressions;
IQueryable<int> q = new[] { 1, 2, 3, 4, 5 }.AsQueryable();
var filtered = q.Where(n => n > 2);
Console.WriteLine(filtered.Expression.NodeType); // Call (a method-call tree)Проверка выражения запроса
Свойство Expression объекта, поддерживающего запросы, предоставляет дерево, которое провайдер преобразует.
using System;
using System.Linq;
var q = new[] { 10, 20, 30 }.AsQueryable().Where(x => x >= 20);
Console.WriteLine(q.Expression.ToString().Contains("Where")); // TrueПреобразование, а не выполнение
Провайдер, например Entity Framework, обходит дерево и формирует SQL, такой как WHERE Age > 18. Ваш предикат C# не выполняется на клиенте: эту работу выполняет база данных.
Роль IQueryProvider
IQueryable содержит IQueryProvider. Когда Вы перебираете запрос, провайдер получает дерево выражений и решает, как его выполнить.
using System;
using System.Linq;
var q = new[] { 1, 2, 3 }.AsQueryable();
Console.WriteLine(q.Provider.GetType().Name); // EnumerableQuery (the in-memory provider)Отложенное выполнение
Дерево преобразуется и выполняется только при переборе (например, с помощью ToList или foreach). До этого момента оно является обычными данными, которые можно продолжать объединять.
using System;
using System.Linq;
var q = new[] { 1, 2, 3, 4 }.AsQueryable()
.Where(n => n > 1)
.Select(n => n * 10);
// nothing has run yet; now force it:
Console.WriteLine(string.Join(",", q.ToList())); // 20,30,40Составление запросов
Поскольку каждый оператор добавляет данные в дерево выражений, Вы можете строить запрос поэтапно, а во время выполнения провайдер увидит его целиком.
using System;
using System.Linq;
var baseQuery = new[] { 5, 15, 25, 35 }.AsQueryable();
var q = baseQuery.Where(n => n > 10);
q = q.Where(n => n < 30); // composed: 10 < n < 30
Console.WriteLine(string.Join(",", q.ToList())); // 15,25Что нельзя преобразовать
Провайдеры могут преобразовать только те операции, которые им понятны. Предикат, вызывающий произвольный метод C#, может вызвать исключение во время выполнения, поскольку ему нет эквивалента в SQL.
Создание собственного провайдера
Пользовательские провайдеры реализуют IQueryProvider и используют ExpressionVisitor, чтобы обойти дерево и преобразовать каждый узел в целевой язык запросов.
Объединение всех элементов
Здесь показана ключевая идея: одна и та же лямбда является делегатом для IEnumerable, но деревом для IQueryable, что позволяет выполнять преобразование.
using System;
using System.Linq;
using System.Linq.Expressions;
Expression<Func<int, bool>> predicate = n => n > 2;
var data = new[] { 1, 2, 3, 4 };
// IEnumerable needs a delegate:
Console.WriteLine(string.Join(",", data.Where(predicate.Compile()))); // 3,4
// IQueryable accepts the tree directly:
Console.WriteLine(string.Join(",", data.AsQueryable().Where(predicate))); // 3,4Быстрая проверка
Убедитесь, что понимаете роль деревьев выражений в провайдерах LINQ.
Повторение
Вы узнали, как провайдеры LINQ используют деревья выражений.
IEnumerableиспользует скомпилированныйFunc, аIQueryable— деревьяExpression<Func>.- Провайдеры преобразуют дерево (например, в SQL), а не выполняют его.
- Выполнение откладывается до перебора.
- Работают только преобразуемые операции; произвольные методы могут вызвать ошибку.
Часто задаваемые вопросы
Урок «Деревья выражений в поставщиках LINQ» бесплатный?
Да — полный текст урока «Деревья выражений в поставщиках LINQ» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Деревья выражений в поставщиках LINQ»?
Узнайте, как поставщики преобразуют выражения в запросы. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Деревья выражений в поставщиках LINQ»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Что такое деревья выражений
- Построение выражений вручную
- Компиляция и выполнение выражений
- Деревья выражений в поставщиках LINQ