Какова цель класса Expression? - PullRequest
55 голосов
/ 14 октября 2011

Мне интересно, в чем именно разница между переносом делегата внутрь Expression<> и не?

Я вижу, что Expression<Foo> часто используется с LinQ, но до сих пор я не нашел ни одной статьи, объясняющей разницу между этим и просто использованием делегата.

1007 * Е.Г. *

Func<int, bool> Is42 = (value) => value == 42;

против

Expression<Func<int, bool>> Is42 = (value) => value == 42;

Ответы [ 6 ]

63 голосов
/ 14 октября 2011

Сохраняя лямбду в качестве делегата, вы сохраняете конкретный экземпляр делегата, который выполняет какое-то действие. Это нельзя изменить, просто позвони. После того, как у вас есть свой делегат, у вас есть ограниченные возможности для проверки того, что он делает, и тому подобное.

Сохраняя лямбда-выражение в качестве выражения, вы сохраняете дерево выражений, представляющее делегат. Им можно манипулировать, чтобы делать другие вещи, такие как изменение его параметров, изменение тела и заставить его делать что-то радикально другое. Он даже может быть скомпилирован обратно делегату, поэтому вы можете вызвать его, если хотите. Вы можете легко проверить выражение, чтобы увидеть, каковы его параметры, что он делает и как он это делает. Это то, что поставщик запросов может использовать, чтобы понять и перевести выражение на другой язык (например, написать запрос SQL для соответствующего дерева выражений).

Также намного проще динамически создавать делегат с использованием выражений, чем при создании кода. Вы можете думать о своем коде на более высоком уровне как о выражениях, которые очень похожи на то, как компилятор просматривает код, вместо того, чтобы переходить на низкий уровень и рассматривать ваш код как инструкции IL.

Таким образом, с выражением вы способны сделать гораздо больше, чем простой анонимный делегат. Хотя это не совсем бесплатно, производительность будет иметь удар, если вы запустите скомпилированные выражения по сравнению с обычным методом или анонимным делегатом. Но это может и не быть проблемой, поскольку другие преимущества использования выражений могут быть важны для вас.

16 голосов
/ 14 октября 2011

Func<> - это просто тип делегата. Выражение - это представление во время выполнения полного дерева операций , которое, при желании, может быть скомпилировано во время выполнения в делегат. Это дерево, которое анализируется синтаксическими анализаторами Expression, такими как Linq-to-SQL, для генерации операторов SQL или выполнения других умных действий. Когда вы назначаете лямбду типу Expression, компилятор генерирует это дерево выражений, а также обычный код IL. Подробнее о деревьях выражений .

12 голосов
/ 14 октября 2011

Чтобы проиллюстрировать другие ответы, если вы скомпилируете эти 2 выражения и посмотрите на код, сгенерированный компилятором, вы увидите:

Func<int, bool> Is42 = (value) => value == 42;

Func<int, bool> Is42 = new Func<int, bool>((@value) => value == 42);


Expression<Func<int, bool>> Is42 = (value) => value == 42;

ParameterExpression[] parameterExpressionArray;
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "value");
Expression<Func<int, bool>> Is42 = Expression.Lambda<Func<int, bool>>(Expression.Equal(parameterExpression, Expression.Constant(42, typeof(int))), new ParameterExpression[] { parameterExpression });
4 голосов
/ 14 октября 2011

Деревья выражений позволяют вам проверять код внутри выражения, в вашем коде.

Например, если вы передали это выражение: o => o.Name, ваш код может обнаружить, что к выражению Name обращаются внутри выражения.

4 голосов
/ 14 октября 2011

Предоставляет базовый класс, из которого получены классы, представляющие узлы дерева выражений.

System.Linq.Expressions.BinaryExpression
System.Linq.Expressions.BlockExpression
System.Linq.Expressions.ConditionalExpression
System.Linq.Expressions.ConstantExpression
System.Linq.Expressions.DebugInfoExpression
System.Linq.Expressions.DefaultExpression
System.Linq.Expressions.DynamicExpression
System.Linq.Expressions.GotoExpression
System.Linq.Expressions.IndexExpression
System.Linq.Expressions.InvocationExpression
System.Linq.Expressions.LabelExpression
System.Linq.Expressions.LambdaExpression
System.Linq.Expressions.ListInitExpression
System.Linq.Expressions.LoopExpression
System.Linq.Expressions.MemberExpression
System.Linq.Expressions.MemberInitExpression
System.Linq.Expressions.MethodCallExpression
System.Linq.Expressions.NewArrayExpression
System.Linq.Expressions.NewExpression
System.Linq.Expressions.ParameterExpression
System.Linq.Expressions.RuntimeVariablesExpression
System.Linq.Expressions.SwitchExpression
System.Linq.Expressions.TryExpression
System.Linq.Expressions.TypeBinaryExpression
System.Linq.Expressions.UnaryExpression

http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx

Дерево выражений представляет выражение linq, которое можетпроанализировать и, например, превратить в запрос SQL.

2 голосов
/ 14 октября 2011

К тому, что написал другой (это совершенно правильно), я добавлю, что через класс Expression вы можете создавать новые методы во время выполнения. Есть некоторые ограничения. Не все, что вы можете сделать в C #, может быть выполнено в дереве Expression (по крайней мере, в .NET 3.5. В .NET 4.0 добавлено большое количество возможных Expression "типов"). Это можно использовать (например) для создания динамического запроса и передачи его в LINQ-to-SQL или для выполнения некоторой фильтрации на основе ввода пользователя ... (вы всегда можете сделать это с CodeDom, если все, что вы хотели был динамический метод, несовместимый с LINQ-to-SQL, но напрямую генерировать IL-код довольно сложно :-))

...