Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Local variable and expression trees

Tags:

c#

lambda

linq

I am learning expression trees in C#.

I am stuck now for a while:

string filterString = "ruby"; Expression<Func<string, bool>> expression = x => x == filterString; 

How can I construct this expression by code? There is no sample how to capture a local variable. This one is easy:

Expression<Func<string, bool>> expression = x => x == "ruby"; 

This would be:

ParameterExpression stringParam = Expression.Parameter(typeof(string), "x"); Expression constant = Expression.Constant("ruby"); BinaryExpression equals = Expression.Equal(stringParam, constant); Expression<Func<string, bool>> lambda1 =     Expression.Lambda<Func<string, bool>>(         equals,         new ParameterExpression[] { stringParam }); 

The debugger prints the following for (x => x == filterString) :

{x => (x == value(Predicate.Program+<>c__DisplayClass3).filterString)}

Thanks for shedding some light on this topic.

like image 955
yonexbat Avatar asked Aug 28 '11 11:08

yonexbat


People also ask

What is expression tree with example?

Each node in an expression tree is an expression. For example, an expression tree can be used to represent mathematical formula x < y where x, < and y will be represented as an expression and arranged in the tree like structure. Expression tree is an in-memory representation of a lambda expression.

What are expression trees used for?

Expression Trees represent code as a structure that you can examine, modify, or execute. These tools give you the power to manipulate code during run time. You can write code that examines running algorithms, or injects new capabilities.

What are C# expression trees?

Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y . You can compile and run code represented by expression trees.

What is expression in LINQ?

LINQ introduced the new type called Expression that represents strongly typed lambda expression. It means lambda expression can also be assigned to Expression<TDelegate> type. The . NET compiler converts the lambda expression which is assigned to Expression<TDelegate> into an Expression tree instead of executable code.


2 Answers

Capturing a local variable is actually performed by "hoisting" the local variable into an instance variable of a compiler-generated class. The C# compiler creates a new instance of the extra class at the appropriate time, and changes any access to the local variable into an access of the instance variable in the relevant instance.

So the expression tree then needs to be a field access within the instance - and the instance itself is provided via a ConstantExpression.

The simplest approach for working how to create expression trees is usually to create something similar in a lambda expression, then look at the generated code in Reflector, turning the optimization level down so that Reflector doesn't convert it back to lambda expressions.

like image 198
Jon Skeet Avatar answered Sep 28 '22 03:09

Jon Skeet


This code wraps the expression in a closure Block that treats the local variable as a constant.

 string filterString = "ruby";   var filterStringParam = Expression.Parameter(typeof(string), "filterString");  var stringParam = Expression.Parameter(typeof(string), "x");   var block = Expression.Block(  // Add a local variable.  new[] { filterStringParam },  // Assign a constant to the local variable: filterStringParam = filterString  Expression.Assign(filterStringParam, Expression.Constant(filterString, typeof(string))),  // Compare the parameter to the local variable  Expression.Equal(stringParam, filterStringParam));   var x = Expression.Lambda<Func<string, bool>>(block, stringParam).Compile(); 
like image 33
Nescio Avatar answered Sep 28 '22 03:09

Nescio