Playing with LINQ Expression Trees

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):

  1. LINQ queries
  2. As a delegate (for example assigning to a delegate)
  3. 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
  • Diagnostics
  • 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.

Advertisements

2 thoughts on “Playing with LINQ Expression Trees

  1. Jamison

    I think you have a small error in your example…

    System.Linq.Expressions.Expression<Func> e = x => x + 5;

    Your generic type should be Func for the body x+5.

    Reply
    1. Steve Horsfield Post author

      Hi Jamison,

      Thanks for the comment, but Func is itself a generic type (with overloads). In this case, I am returning an integer which is a mistake against my coding, and taking an integer as a parameter, so the type should be Func<int,int>. Originally, I was playing with a LINQ where clause and returning (x > 5) which is Func as per my original text.

      Thanks for pointing out the error.

      The corrected text is:

      System.Linq.Expressions.Expression<Func<int,bool>> e = x => x > 5;

      Note: I’ll update the post text to reflect this. Thanks again.

      Note: I’m guessing WordPress removed your template parameters (as it did mine!)

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s