In this post, we are going to discuss the topic on the Expression Tree and Delegate and Lambda, we are going to go through from simple expresison, then expression converted to delegate (lambda), and then we shape up/build up to a more complicated Expression Tree example and we compare it with its equivalent Lambda expression, later we shows why behind Expression Tree since we have the lambda expresion which has hte nice compile time check.
Code as Data
Code as Data is a long existed idea. But it hasn't bee used much in popular programming language. Expression Tree in .NET provides an abstract way of representing the code as a tree of objects. It's like COdeDOM but operate at a slightly higher level. The primary use of Expression tree is in LINQ and you can custom Expression to enable code execution in another end (or even language)
Expression Trees
The namespace in question is "System.Linq.Expression" , of all the classes that is contained in this namespace, Expression is the one that you may use most.
Build a simple expression tree
Let's first see an simple example of Building a exprssion tree
public static void ExploratoryExample() { Expression firstArg = Expression.Constant(2); Expression secondArg = Expression.Constant(3); Expression add = Expression.Add(firstArg, secondArg); Console.WriteLine(add); // this will evaluation the expression tree and does not execute the expression treee, it will print some string representation of the Linq Expression Tree // something like (1 + 2) }
It does almost trivial, it creates two Constant Expression and then made a call Expresion to glue the two together, Graphical representaion is as follow
In the Expression class, there are two properties
Type: the .NET type of the evaluated Expression
NodeType: returns the kind of expression represented , as a member of ExpressoinType enumeration,with values such as LessThan....
As you already know, we have build the ExpressionTree, but we can do barely anything with it, except, Expression has a Compile method which will turnst the Tree representaion of the expresion into executable code piece - a delegate. Below shows how.
public static void ExploratoryExample()
{
// build expression tree as above
// ...
Func<int> compiled = Expression.Lambda<Func<int>>(add).Compile(); // Lambda expression can compiled, and once compiled
// you can execute it
Console.WriteLine("compiled() = {0}", compiled());
}
Now, you will get 5 if you execute the compiled delegate (Func<T> in this case)...
Converting a expression to a expression tree
So this is the other way around of the conversion, and it has a lot of use implicaiton, suppose that you have some code (which is static checked and compiled by the Compiler) and you can convert that readily to expression tree.
A very eimple way of doing that is as follow
// initialize a expression with a delegate
// initialization as the conversion
Expression<Func<int>> returns5 = () => 5;
// you can compile the Expression back to lambda/delegate, as before
Func<int> compiled = returns5.Compile();
Console.WriteLine("compiled() = {0}", compiled());
However, the conversion has limitation. In example
- You cannot convert a block of statement (even just one return statement), only single expression is supported
- The expression cannot have assignment
but the list is not exhausted. You will find more at compile time when make such attempt.
To get into details how things works, let see a more complicated expression tree example .Here is the lambda expression code.
Expression<Func<string, string, bool>> expression = (x, y) => x.StartsWith(y); var compiled = expression.Compile(); Console.WriteLine(compiled("First", "Second")); Console.WriteLine(compiled("First", "Fir"));
now let's try to build the expression that matches the code above. This is what we get.
MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); var target = Expression.Parameter(typeof(string), "x"); // ((string)x).Method(...) var methodArg = Expression.Parameter(typeof(string), "y"); // x.Method((string) y) Expression[] methodArgs = new[] { methodArg }; // methods args -- composite -->* methodArg Expression call = Expression.Call(target, method, methodArgs); // x.StartsWith(y) var lambdaParamters = new[] { target, methodArg }; // (x, y) -- (target, methodArgs) -- (arg1, arg2) => ... // it is difficult to figure out the argument types //var lambda = Expression.Lambda(call, methodArgs); // so you would probably indicate what is the type of the Lambda expression var lambda = Expression.Lambda<Func<string, string, bool>> (call, lambdaParamters); var compiled = lambda.Compile(); Console.WriteLine("First", "Second"); Console.WriteLine("First", "Fir");
A bit chunky, let's see the Expresion tree in its Graphic representation. See below.
HINT, you can visualize the Expression Tree from the Text Visualizer.
Expression Tree at the heart of LINQ.
Without lambda expresison, Expression Tree would have little value. They'd be an alternative to CodeDOM.
It is also ture for the reverse to a limited extent: without expression trees, lambda expression would certainmly be less useful. HAVing a more compact way of creating delegate would be welcome, and hte shift towards a more functinal development model would still be viable. Lambda expression are particular effective when combined with extension methods. But with expresion tree in the picture as well, things get a lot more interesting.
Lambda expression provide:
Compile-check
Expression Tree provides:
abstract the execution model away from the desired logic.
LINQ to SQL is good example of combination of Lamdba Expression and Expression Tree.