1. Computing & Technology

Discuss in my forum

Expression Trees

Introduced for LINQ, expression trees make LINQ queries efficient and flexible.

By , About.com Guide

Updated January 28, 2012

Since it was introduced in VB.NET 2008, LINQ has become fundamental in VB.NET - but it's still widely misunderstood. This article is one of a series at About Visual Basic that covers the major ways to program LINQ. The goal is for a beginning Visual Basic .NET programmer to get up to speed on LINQ. If you found this article from a search and you would like to start at the beginning, you can find an introduction to the overall LINQ technology - what it covers and what you can do with it - in the article LINQ - An Example Driven Introduction with an example showing how LINQ could be used to start web pages using selections made with CheckBox controls. There is an index to all of the articles in the series in the beginning of the article.

LINQ Queries and Expression Trees - A Comparison

You may never have the kind of problem that expression trees can solve, but if you do, they can make a tremendous difference. But they're a different kind of coding. To see the difference, let's look at the same problem solved with both a LINQ query and an expression tree style of coding.

This initial example is very simple by design since the purpose is to simply contrast a standard LINQ query with an expression tree. The comparison isn't too direct since the two technologies aren't designed to solve the same problems. But the goal right now is to simply understand what an expression tree does. Seeing the difference between an expression tree and a LINQ query can help you figure it out.

In this simple example, a query returns the upper case characters, "A" and "C", from an array of elements of type Char.


Dim charArray() As Char =
    {"A", "b", "C", "d"}

The LINQ query to do this is straightforward. (If you need a refresher on LINQ queries, I cover it in this article: LINQ and Queries.)


Console.WriteLine("LINQ Query Result")
Dim LINQ_Query As IEnumerable(Of Char) =
    charArray.Where(
        Function(theChar) Asc(theChar) > 64 And
                          Asc(theChar) < 91)
For Each theChar In LINQ_Query
    Console.WriteLine(theChar)
Next

LINQ returns an array and the For-Next loop simply displays everything in the array.

The expression tree equivalent isn't quite so straightforward since the result isn't an array of elements, but rather the expression tree itself. This expression isn't initially executable code for a very good reason. The purpose of the expression tree is to be executed against a data store that doesn't even have to be on the same machine and might even have it's own execution engine, like SQL Server. To make this example work, the expression tree has to be compiled for the array that will be queried first. (You can see that in the code below.) And then the compiled expression tree has to be used to get the actual result from the array. Here's the code.


Console.WriteLine("Expression Tree Result")
Dim LINQ_ExpressionTree _
    As Expression(Of Func(Of Char, Boolean)) =
    Function(theChar) (Asc(theChar) > 64) And
                       (Asc(theChar) < 91)
Dim ExecutableExpressionTree As Func(Of Char, Boolean) =
    LINQ_ExpressionTree.Compile()
For Each charElement In charArray
    If ExecutableExpressionTree(charElement) = True Then _
        Console.WriteLine(charElement)
Next

The end result is the same, however, as shown below.

--------
Click Here to display the illustration
--------

Expression trees are useful in two types of situations:

-> When complex queries against large data stores have to be used. An expression tree can be compiled and executed against the data store just once to get the final result. A standard LINQ query would normally require two queries against a data store to both retrieve data and order it but an expression tree could do it in a single query.
-> When dynamic queries have to be used. An expression tree can be variable depending on previous results and then compiled.

The simple example above doesn't do much to illustrate these differences, but the Expression class has methods that allow you to write code that will compose an expression from the individual components or decompose an existing expression into components. Here's the code to decompose the query shown in the example:


Dim param As ParameterExpression =
    LINQ_ExpressionTree.Parameters(0)
Dim operation As BinaryExpression =
    LINQ_ExpressionTree.Body
Dim left As BinaryExpression =
    operation.Left
Dim right As BinaryExpression =
    operation.Right
Console.WriteLine(String.Format(
    "Function({0}) {1} {2}" &
    vbCrLf & "{3}",
    param.Name, left,
    operation.NodeType, right))

This gives you exactly the same expression shown in the code above:


Function(theChar) (Asc(theChar) > 64) And
(Asc(theChar) < 91)

--------
Click Here to display the illustration
--------

Since similar methods are available to compose an expression, you have quite a bit of flexibility in building them in code if you need it.

©2012 About.com. All rights reserved.

A part of The New York Times Company.