Книга: C# 4.0: полное руководство
Деревья выражений
Деревья выражений
Еще одним средством, связанным с LINQ, является дерево выражений, которое представляет лямбда-выражение в виде данных. Это означает, что само лямбда-выражение нельзя выполнить, но можно преобразовать в исполняемую форму. Деревья выражений инкапсулируются в классе System.Linq.Expressions.Expression<TDelegate>
. Они оказываются пригодными в тех случаях, когда запрос выполняется вне программы, например средствами SQL в базе данных. Если запрос представлен в виде данных, то его можно преобразовать в формат, понятный для базы данных. Этот процесс выполняется, например, средствами LINQ to SQL в интегрированной среде разработки Visual Studio. Таким образом, деревья выражений способствуют поддержке в C# различных баз данных.
Для получения исполняемой формы дерева выражений достаточно вызвать метод Compile()
, определенный в классе Expression
. Этот метод возвращает ссылку, которая может быть присвоена делегату для последующего выполнения. А тип делегата может быть объявлен собственным или же одним из предопределенных типов делегата Func
в пространстве имен System
. Две формы делегата Func
уже упоминались ранее при рассмотрении методов запроса, но существует и другие его формы.
Деревьям выражений присуще следующее существенное ограничение: они могут представлять только одиночные лямбда-выражения. С их помощью нельзя представить блочные лямбда-выражения.
Ниже приведен пример программы, демонстрирующий конкретное применение дерева выражений. В этой программе сначала создается дерево выражений, данные которого представляют метод, определяющий, является ли одно целое число множителем другого. Затем это дерево выражений компилируется в исполняемый код. И наконец, в этой программе демонстрируется выполнение скомпилированного кода.
// Пример простого дерева выражений.
using System;
using System.Linq;
using System.Linq.Expressions;
class SimpleExpTree {
static void Main() {
// Представить лямбда-выражение в виде данных.
Expression<Func<int, int, bool>>
IsFactorExp = (n, d) => (d != 0) ? (n % d) == 0 : false;
// Скомпилировать данные выражения в исполняемый код.
Func<int, int, bool>
IsFactor = IsFactorExp.Compile();
// Выполнить выражение,
if(IsFactor(10, 5))
Console.WriteLine("Число 5 является множителем 10.");
if(!IsFactor(10, 7))
Console.WriteLine("Число 7 не является множителем 10.");
Console.WriteLine();
}
}
Вот к какому результату приводит выполнение этой программы.
Число 5 является множителем 10.
Число 7 не является множителем 10.
Данный пример программы наглядно показывает два основных этапа применения дерева выражений. Сначала в ней создается дерево выражений с помощью следующего оператора.
Expression<Func<int, int, bool»
IsFactorExp = (n, d) => (d != 0) ? (n % d) == 0 : false;
В этом операторе конструируется представление лямбда-выражения в оперативной памяти. Как пояснялось выше, это представление доступно по ссылке, присваиваемой делегату IsFactorExp
. А в следующем операторе данные выражения преобразуются в исполняемый код.
Func<int, int, bool>
IsFactor = IsFactorExp.Compile();
После выполнения этого оператора делегат IsFactorExp
может быть вызван, чтобы определить, является ли одно целое число множителем другого.
Обратите также внимание на то, что <Func<int, int, bool>
обозначает тип делегата. В этой форме делегата Funс
указываются два параметра типа int и возвращаемый тип bool
. В рассматриваемой здесь программе использована именно эта форма делегата Funс
, совместимая с лямбда-выражениями, поскольку для выражения требуются два параметра. Для других лямбда-выражений могут подойти иные формы делегата Funс
в зависимости от количества требуемых параметров. Вообще говоря, конкретная форма делегата Funс
должна удовлетворять требованиям лямбда-выражения.
- Основы LINQ
- Общая форма запроса
- Отбор запрашиваемых значений с помощью оператора where
- Сортировка результатов запроса с помощью оператора orderby
- Подробное рассмотрение оператора select
- Применение вложенных операторов from
- Группирование результатов с помощью оператора group
- Продолжение запроса с помощью оператора into
- Применение оператора let для создания временной переменной в запросе
- Объединение двух последовательностей с помощью оператора join
- Анонимные типы
- Создание группового объединения
- Методы запроса
- Режимы выполнения запросов: отложенный и немедленный
- Деревья выражений
- Методы расширения
- PLINQ
- Деревья аннулирования сертификатов
- Красно-черные деревья
- 3. Null-значения и общее правило вычисления выражений
- Как использовать технику разговорных выражений
- Разбор XPath-выражений
- 14.4.1. Введение в двоичные деревья
- Виды выражений
- Глава 8. Бинарные деревья.
- 14.4.2. Функции управления деревьями
- Списки и деревья областей памяти
- Поиск файлов с использованием регyлярных выражений
- 2.21. Включение выражений в строку