Я манекен в этом сценарии.
Я пытался прочитать в Google, что это такое, но не понимаю. Может ли кто-нибудь дать мне простое объяснение того, что это такое и почему они полезны?
edit: я говорю о функции LINQ в .Net.
Я манекен в этом сценарии.
Я пытался прочитать в Google, что это такое, но не понимаю. Может ли кто-нибудь дать мне простое объяснение того, что это такое и почему они полезны?
edit: я говорю о функции LINQ в .Net.
Ответы:
Лучшее объяснение деревьев выражений, которое я когда-либо читал, - это статья Чарли Калверта.
Подвести итог;
Дерево выражений представляет то, что вы хотите сделать, а не то, как вы хотите это делать.
Это наиболее важное различие между делегатами и выражениями. Вы вызываете
function
(aFunc<int, int, int>
), даже не зная, что он будет делать с двумя переданными вами целыми числами. Он берет два и возвращает один, это все, что может знать ваш код.Теперь, в отличие от делегатов, ваш код может знать, для чего предназначено дерево выражений.
Это означает, что вы не можете просто вызвать дерево выражений, как вы могли бы вызвать делегата, но вы можете проанализировать его. Итак, что может понять ваш код, анализируя переменную
expression
?// `expression.NodeType` returns NodeType.Lambda. // `expression.Type` returns Func<int, int, int>. // `expression.ReturnType` returns Int32. var body = expression.Body; // `body.NodeType` returns ExpressionType.Add. // `body.Type` returns System.Int32. var parameters = expression.Parameters; // `parameters.Count` returns 2. var firstParam = parameters[0]; // `firstParam.Name` returns "a". // `firstParam.Type` returns System.Int32. var secondParam = parameters[1]. // `secondParam.Name` returns "b". // `secondParam.Type` returns System.Int32.
Здесь мы видим, что выражение дает нам много информации.
Но зачем нам это нужно?
И снова мы видим, что деревья выражений позволяют нам представлять (выражать?) То, что мы хотим сделать. И мы пользуемся услугами переводчиков, которые решают, как наши выражения используются.
источник
Дерево выражений - это механизм преобразования исполняемого кода в данные. Используя дерево выражений, вы можете создать структуру данных, которая представляет вашу программу.
В C # вы можете работать с деревом выражений, созданным лямбда-выражениями, с помощью
Expression<T>
класса.В традиционной программе вы пишете такой код:
double hypotenuse = Math.Sqrt(a*a + b*b);
Этот код заставляет компилятор генерировать присваивание, и все. В большинстве случаев это все, что вас волнует.
В обычном коде ваше приложение не может вернуться назад и посмотреть,
hypotenuse
чтобы определить, что оно было создано путем выполненияMath.Sqrt()
вызова; эта информация просто не является частью того, что включено.Теперь рассмотрим лямбда-выражение, подобное следующему:
Func<int, int, double> hypotenuse = (a, b) => Math.Sqrt(a*a + b*b);
Это немного отличается от прежнего. Теперь
hypotenuse
это фактически ссылка на блок исполняемого кода . Если вы позвонитеhypotenuse(3, 4);
вы получите
5
возвращенное значение .Мы можем использовать деревья выражений для исследования созданного блока исполняемого кода. Попробуйте вместо этого:
Expression<Func<int, int, int>> addTwoNumbersExpression = (x, y) => x + y; BinaryExpression body = (BinaryExpression) addTwoNumbersExpression.Body; Console.WriteLine(body);
Это производит:
С деревьями выражений возможны более сложные техники и манипуляции.
источник
Деревья выражений - это представление выражения в памяти, например арифметическое или логическое выражение. Например, рассмотрим арифметическое выражение
a + b*2
Поскольку * имеет более высокий приоритет оператора, чем +, дерево выражений строится следующим образом:
[+] / \ a [*] / \ b 2
Имея это дерево, его можно оценить для любых значений a и b. Кроме того, вы можете преобразовать его в другие деревья выражений, например, чтобы получить выражение.
Когда вы реализуете дерево выражений, я бы предложил создать Expression базового класса . Производный от этого класс BinaryExpression будет использоваться для всех двоичных выражений, таких как + и *. Затем вы можете ввести VariableReferenceExpression для ссылочных переменных (таких как a и b) и другой класс ConstantExpression (для 2 из примера).
Дерево выражения во многих случаях строится в результате синтаксического анализа входных данных (напрямую от пользователя или из файла). Для оценки дерева выражений я бы предложил использовать шаблон Visitor .
источник
Краткий ответ: приятно иметь возможность написать такой же запрос LINQ и указать его на любой источник данных. Без него у вас не было бы запроса "Language Integrated".
Длинный ответ: как вы, наверное, знаете, когда вы компилируете исходный код, вы переводите его с одного языка на другой. Обычно с языка высокого уровня (C #) на более низкий уровень (IL).
В основном это можно сделать двумя способами:
Последнее - то, что делают все программы, известные нам как «компиляторы».
Если у вас есть дерево синтаксического анализа, вы можете легко перевести его на любой другой язык, и это то, что деревья выражений позволяют нам делать. Поскольку код хранится в виде данных, вы можете делать с ним все, что захотите, но, возможно, вы просто захотите перевести его на какой-нибудь другой язык.
Теперь в LINQ to SQL деревья выражений превращаются в команду SQL, а затем отправляются по сети на сервер базы данных. Насколько я знаю, они не делают ничего особенного при переводе кода, но могли . Например, поставщик запросов может создавать различный код SQL в зависимости от условий сети.
источник
IIUC, дерево выражений похоже на абстрактное синтаксическое дерево, но выражение обычно дает одно значение, тогда как AST может представлять всю программу (с классами, пакетами, функцией, операторами и т. Д.)
В любом случае, для выражения (2 + 3) * 5 дерево будет:
* / \ + 5 / \ 2 3
Оцените каждый узел рекурсивно (снизу вверх), чтобы получить значение в корневом узле, то есть значение выражения.
Конечно, у вас могут быть унарные (отрицание) или тройные (если-то-еще) операторы, а также функции (n-арные, т.е. любое количество операций), если ваш язык выражений позволяет это.
Оценка типов и управление типами выполняется для похожих деревьев.
источник
Деревья выражений DLR являются дополнением к C # для поддержки среды выполнения динамического языка (DLR). DLR также отвечает за предоставление нам метода объявления переменных "var". (
var objA = new Tree();
)Подробнее о DLR .
По сути, Microsoft хотела открыть CLR для динамических языков, таких как LISP, SmallTalk, Javascript и т. Д. Для этого им нужно было иметь возможность анализировать и оценивать выражения на лету. Это было невозможно до появления DLR.
Вернемся к моему первому предложению: деревья выражений - это дополнение к C #, открывающее возможность использования DLR. До этого C # был гораздо более статическим языком - все типы переменных нужно было объявлять как определенный тип, и весь код приходилось писать во время компиляции.
Использование с данными
деревьями выражений открывает шлюзы для динамического кода.
Скажем, например, что вы создаете сайт о недвижимости. На этапе проектирования вы знаете все фильтры, которые можно применить. Для реализации этого кода у вас есть два варианта: вы можете написать цикл, который сравнивает каждую точку данных с серией проверок If-Then; или вы можете попытаться создать запрос на динамическом языке (SQL) и передать его программе, которая может выполнить поиск за вас (база данных).
С помощью деревьев выражений теперь вы можете изменять код в своей программе на лету и выполнять поиск. В частности, это можно сделать через LINQ.
(См. Также: MSDN: Как использовать деревья выражений для создания динамических запросов. ).
Помимо данных
В основном деревья выражений используются для управления данными. Однако их также можно использовать для динамически генерируемого кода. Итак, если вам нужна функция, которая определяется динамически (например, Javascript), вы можете создать дерево выражений, скомпилировать его и оценить результаты.
Я бы пошел немного глубже, но этот сайт работает намного лучше:
Деревья выражений как компилятор
Перечисленные примеры включают создание универсальных операторов для типов переменных, лямбда-выражений, изменяемых вручную, высокопроизводительное неглубокое клонирование и динамическое копирование свойств чтения / записи из одного объекта в другой.
Сводные
деревья выражений - это представления кода, который компилируется и оценивается во время выполнения. Они позволяют использовать динамические типы, что полезно для работы с данными и динамического программирования.
источник
var
является синтаксическим сахаром времени компиляции - он не имеет ничего общего с деревьями выражений, DLR или средой выполнения.var i = 0
компилируется, как если бы вы написалиint i = 0
, поэтому вы не можете использовать егоvar
для представления типа, который не известен во время компиляции. Деревья выражений не являются «дополнением для поддержки DLR», они введены в .NET 3.5 для поддержки LINQ. DLR, с другой стороны, представлен в .NET 4.0, чтобы разрешить использование динамических языков (например, IronRuby) иdynamic
ключевое слово. Деревья выражений фактически используются DLR для обеспечения взаимодействия, а не наоборот.Является ли дерево выражений, на которое вы ссылаетесь, деревом оценки выражений?
Если да, то это дерево, построенное парсером. Parser использовал Lexer / Tokenizer для идентификации токенов из программы. Parser строит двоичное дерево из токенов.
Вот подробное объяснение
источник