Expression trees represent code in a tree-like data structure,
where each node is an expression. You can compile and run code represented by
expression trees. This enables dynamic modification of executable code.
When a lambda expression is assigned to a variable of type Expression, the compiler
emits code to build an expression tree that represents the lambda expression.
The Expression tree can be parsed as shown below. Next come the compiling of
the expression tree and then execute. Only expression trees that represent
lambda expressions can be executed. Expression trees that represent lambda
expressions are of type LambdaExpression or Expression. To execute these
expression trees, call the Compile method to create an
executable delegate, and then invoke the delegate.
//Creating Expression
Trees from Lambda Expressions
Expression<Func<int, bool>> lambda = num => num < 5;
//Parsing
Expression Trees
ParameterExpression
param = (ParameterExpression)lambda.Parameters[0];
BinaryExpression
operation = (BinaryExpression)lambda.Body;
ParameterExpression
l = (ParameterExpression)operation.Left;
ConstantExpression
r = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, l.Name,
operation.NodeType, r.Value);
// Compiling
the expression tree into a delegate.
Func<int, bool> result
= lambda.Compile();
// Invoking the
delegate and writing the result to the console.
Console.WriteLine("Result for execution - {0}",result(4));
To create expression trees
by using the API, use the Expression class. This class contains static factory methods that create
expression tree nodes of specific types, for example, ParameterExpression, which represents a variable or parameter,
or MethodCallExpression, which represents
a method call. ParameterExpression, MethodCallExpression, and the other expression-specific types
are also defined in the System.Linq.Expressions namespace. These types derive from the abstract type Expression. Now we will see
how we can create the Above stated expression unsing Expression class.
//Creating Expression Trees by Using the API
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>>
lambda1 = Expression.Lambda<Func<int, bool>>(
numLessThanFive,
new
ParameterExpression[] { numParam });
Once you keep a breakpoint you see the following –
In .NET Framework 4, the expression trees API also supports
assignments and control flow expressions such as loops, conditional blocks, and try-catch blocks. By using the API, you can
create expression trees that are more complex than those that can be created
from lambda expressions by the C# and Visual Basic compilers.
Expression trees should be immutable. This means that if you want
to modify an expression tree, you must construct a new expression tree by
copying the existing one and replacing nodes in it. You can use an expression
tree visitor to traverse the existing expression tree.
Use Expression
Trees to Build Dynamic Queries
Expression trees are also used in LINQ to represent lambda
expressions that are assigned to variables of type Expression.
The following example shows you how to use expression trees to
construct a query against an IQueryable data source and then execute it. The
code builds an expression tree to represent the following query:
//Creating the follwoinh C# Query :
companies.Where(company => (company.ToLower() == "coho
winery" || company.Length > 16)).OrderBy(company => company)
// The IQueryable data to query.
IQueryable<String>
queryableData = companies.AsQueryable<string>();
// Compose the expression tree that represents the parameter to
the predicate.
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
// ***** Where(company => (company.ToLower() == "coho
winery" || company.Length > 16)) *****
// Create an expression tree that represents the expression
'company.ToLower() == "coho winery"'.
Expression left = Expression.Call(pe,
typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Expression right = Expression.Constant("coho winery");
Expression e1 = Expression.Equal(left,
right);
// Create an expression tree that represents the expression
'company.Length > 16'.
left
= Expression.Property(pe, typeof(string).GetProperty("Length"));
right
= Expression.Constant(16, typeof(int));
Expression e2 = Expression.GreaterThan(left,
right);
// Combine the expression trees to create an expression tree that
represents the
// expression '(company.ToLower() == "coho winery" ||
company.Length > 16)'.
Expression predicateBody = Expression.OrElse(e1,
e2);
// Create an expression tree that represents the expression
// 'queryableData.Where(company => (company.ToLower() ==
"coho winery" || company.Length > 16))'
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new
Type[] { queryableData.ElementType },
queryableData.Expression,
Expression.Lambda<Func<string, bool>>(predicateBody, new
ParameterExpression[] { pe }));
// ***** End Where *****
// ***** OrderBy(company => company) *****
// Create an expression tree that represents the expression
// 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderByCallExpression = Expression.Call(
typeof(Queryable),
"OrderBy",
new
Type[] { queryableData.ElementType,
queryableData.ElementType },
whereCallExpression,
Expression.Lambda<Func<string, string>>(pe, new
ParameterExpression[] { pe }));
// ***** End OrderBy *****
// Create an executable query from the expression tree.
IQueryable<string>
results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);
// Enumerate the results.
foreach (string company
in results)
Console.WriteLine(company);