Well, LINQ has been around for a while now and I suppose many of you have been playing with (I mean using) it in both production and hobby code. One of the core features that LINQ requires is the ability to express lambda expressions as expression trees rather than delegates. Delegates represent compiled (and thus opaque) code, but expression trees can be manipulated for optimisation and language translation, such as to SQL.
Now LINQ does that all for you, but have you ever wondered whether you can make an expression tree directly?
The answer is yes, although with two caveats (see below). The translation from a lambda expression to an expression tree is performed by the compiler. However, you can only use lambda expressions in a few ways (that I am aware of):
- LINQ queries
- As a delegate (for example assigning to a delegate)
- As a delegate expression tree
So what are the caveats?
- An expression tree cannot represent a lambda expression that has a statement body
- You have to specify the types when you convert the lambda expression to an expression tree
So how do you do it? Easily, for example:
System.Linq.Expressions.Expression<Func<int,bool>> e = x => x > 5;
Note: the code has been updated because of an error in the original post (thanks to Jamison for pointing out the problem) – the original code was “x => x + 5”
This gets really interesting when you use complex expressions. You can use the side effects of a function call to achieve the behaviour of statement blocks and you can manipulate expression trees directly, thereby combining one expression tree with another. This is essentially what LINQ is doing for you behind the scenes and it is why it is possible to delay both the execution and the construction of the execution method until after the expression has been fully constructed, and this allows for optimisation. If you are interested, you might want to learn about monads in functional programming. Watch this Channel9 video for an introduction: http://channel9.msdn.com/shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads.
So, what can this technique be used for?
- Unit testing of expression tree values and calculations
- Developing domain specific language translations of C# code
- Treating expressions as parameters (for example c.Select(exprTree))
- Automatic instrumentation of programs (by editing the expression tree before compilation)
However, not all IEnumerable types support expression trees. For those that don’t, you have to use delegates but then it is fairly easy to pass delegates around. You can also convert an expression tree into a delegate at runtime, possibly after you’ve changed it.