Languages - DevSource
DevSource: Microsoft Developer Resource DevSource Home Sponsored by Microsoft Home Add Ons Architecture Languages Techniques Using VS Forums
Home arrow Languages arrow Page 2 - Understanding and Using LINQ Expression Trees
Understanding and Using LINQ Expression Trees
By John Mueller

Rate This Article: Add This Article To:

Understanding and Using LINQ Expression Trees - Creating an Expression Tree
( Page 2 of 3 )

Creating an Expression Tree

As previously stated, an expression tree is a tree-like structure that contains expressions used to process your data. The advantage of an expression tree is that you can build it out of bits and pieces or you can choose to let Visual Studio build it for you. Listing 4 shows the expression tree version of the example.

Listing 4: Using a Expression Tree to Perform the Check

private void btnExpression_Click(object sender, EventArgs e)
{
   // Create a test array.
   String[] TestStrings = 
      { "One", "Two", "Three", "Four", "Five", "Six" };
   // Create an output variable.
   String Message = "";
   // Define the expression tree, what you want
   // the expression to do.
   Expression<Func<String,Boolean>> ShortString =
      Value => Value.Length <= 3;
   // Check for short strings using the expression.
   foreach (String ThisString in TestStrings)
      if (ShortString.Compile().Invoke(ThisString))
         Message = Message + ThisString + "\r\n";
   MessageBox.Show(Message);
}
ADVERTISEMENT

In this case, the code doesn’t call CheckStrings() at all. Everything occurs within the btnExpression_Click() method. You can build the expression from pieces using the classes in the System.Linq.Expressions namespace, or you can use the technique shown here. The result is an expression tree that you compile and invoke using the Compile() and Invoke() methods, as shown. The advantage to using an expression tree is that you can build the components as needed.

The expression tree portion of the example begins by creating what looks like a complex piece of code, but it’s not once you know how the code is put together. The Expression<T> class accepts a delegate prototype as input. You define the delegate using the Func<T, TResult> generic delegate. In this case, the generic delegate accepts a String as input and outputs a Boolean. However, you can provide any input or output types needed by your application.

The definition of the expression comes next. ShortString contains a lambda expression that outputs a Boolean value that determines when a string is less than or equal to three characters in length. At this point, ShortString actually contains a tree structure that includes all the elements required for the lambda expression MyString => MyString.Length > 3.

To output the information, the application uses a foreach loop. The code calls the Compile().Invoke() method of ShortString and supplies the current string from the array of test values. The result is a string that contains a list of the output values, which the application then displays on screen.

Building an Expression Tree from Scratch

Now, let’s say that you want to create the lambda expression shown in Listing 4 from scratch. You may want to include some features that would be hard to express using a standard lambda expression. In this case, you need to use the same classes and methods that the compiler uses in the background to create the lambda expression. Listing 5 is the same lambda expression as shown in Listing 4. The difference is that we’re now building this expression tree completely from scratch.

Listing 5: Building an Expression Tree from Scratch

private void btnCreate_Click(object sender, EventArgs e)
{
   // Create a test array.
   String[] TestStrings = 
      { "One", "Two", "Three", "Four", "Five", "Six" };
   // Create an output variable.
   String Message = "";
   // Create a parameter to use within the expression. To do
   // this, you must create the parameter, a list of those
   // parameters, and then place them in a read-only collection.
   ParameterExpression Value = 
      Expression.Parameter(typeof(String), "Value");
   List<ParameterExpression> ValueList = 
      new List<ParameterExpression>();
   ValueList.Add(Value);
   ReadOnlyCollection<ParameterExpression> PECollection = 
      new ReadOnlyCollection<ParameterExpression>(ValueList);
   // Define a member expression for the 
   // left side of the comparison.
   PropertyInfo ValueLength = 
      typeof(String).GetProperty("Length");
   MemberExpression Left = 
      Expression.MakeMemberAccess(Value, ValueLength);
   // Define a constant expression for
   // the right side of the comparison.
   ConstantExpression Right = Expression.Constant(3);
   // Create the comparison expression.
   BinaryExpression Compare = 
      Expression.LessThanOrEqual(Left, Right);
   // Create the lambda expression.
   LambdaExpression LE = 
      Expression.Lambda<Func<String, Boolean>>(
         Compare, PECollection);
   // Cast the lambda expression to an expression tree.
   Expression<Func<String, Boolean>> ShortString = 
      (Expression<Func<String, Boolean>>)LE;
   // Compile the function.
   Func<String, Boolean> TestMe = 
      (Func<String, Boolean>)LE.Compile();
   // Check for short strings using the expression.
   foreach (String ThisString in TestStrings)
      if (TestMe(ThisString))
         Message = Message + ThisString + "\r\n";
   MessageBox.Show(Message);
}

It’s time to remember the discussion about the tree-like structure of lambda expressions. Here you see that structure exposed. The code begins by creating the left side of the lambda expression, the parameter Value. It begins by defining a new ParameterExpression named Value of type String. You can use multiple parameters in lambda expressions, so you have to place the parameters in a List<ParameterExpression> object. Since we’re not planning to modify the parameter inside the lambda expression, the code places the list in a ReadOnlyCollection<ParameterExpression> collection.

Now that you have a parameter to use, you can begin creating the body (the right side) of the lambda expression. Remember that the body consists of three elements: property (Value.Length), comparison (<=), and constant (3). The code begins with the property. The example uses the Value.Length property, so the code defines a MemberAccess type from a MemberExpression object. The MemberExpression object requires two inputs: the Value ParameterExpression and the ValueLength PropertyInfo object. Notice the technique used to create the PropertyInfo object—you use the String type to obtain the Length property information.

Creating a constant expression comes next. In this case, all you need to do is use the Expression.Constant() method to create the ConstantExpression object.

At this point, you have the property and the constant. It’s time to combine them into a BinaryExpression object, Compare, that provides the comparison operator. The code uses the Expression.LessThanOrEqual() method to perform this task. Make sure you get the Left and Right objects in the correct place because the code will compile with them in either order, but the lambda expression won’t work properly.

Creating the LambdaExpression object, LE is next. To perform this task, you combine the parameters with the other expressions you’ve created. Make certain that you define your template correctly or the compiler will complain. If the compiler does manage to create the LambdaExpression, you’ll get an "Incorrect number of parameters supplied for lambda declaration" error during runtime.

You can’t execute a LambdaExpression object—you must cast it into an Expression object, as shown next. The Microsoft example at http://msdn.microsoft.com/en-us/library/bb882536.aspx shows the whole process in one step, but I wasn’t able to get this to work. Every time I tried to combine the creating the LambdaExpression object with casting it as an Expression object, I received the "Incorrect number of parameters supplied for lambda declaration" error. Interestingly enough, using two constants as shown in their example works just fine.

Listing 4 shows the code compiling the expression tree during each loop. This practice is actually inefficient, but I wanted to make that example as simple as possible. The code in Listing 5 shows how to do things correctly. The next step compiles the expression tree. You then invoke the expression tree, as shown in the foreach loop.



 
 
>>> More Languages Articles          >>> More By John Mueller
 



Microsoft's Future: A Chat With Their CTO, Barry Briggs

Play Video >

All Videos >

Julia explores the Robotics Studio!

Read now >

Messages to Bill Gates!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.