2011-10-14 2 views
43

Мне интересно, какая именно разница между обертыванием делегата внутри Expression<> и нет?Какова цель класса Expression?

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

E.g.

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

против

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

ответ

48

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

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

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

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

+0

Это прояснило это для меня, спасибо большое :-) – Steffen

13

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

4

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

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 запрос.

4

Expression Trees позволяет вам проверять код внутри выражения в вашем коде.

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

9

Чтобы проиллюстрировать другие ответы, если вы собираете эти 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 }); 
+0

Хорошо, в какой момент вы пытаетесь сделать ? – Phil

+4

Он спрашивал, в чем были отличия, и сгенерированный код был само собой разумеющимся. – Ucodia

2

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

Смежные вопросы