Introduction
Expressions and Func & Action are generic classes and often developers gets confused with them. E.g. which one to use and when. As most of C# developer are familiar with LINQ (Language Integrated Query) so they’re familiar with Lambda Expressions. In this post we’ll not be discussing Func<> and Action<>, Long time back I already wrote a post about LambdaExpression and Delegate templates.
We’ll be focusing on how expressions is different from Delegate templates and what benefits you can get by learning and getting familiar with it.
Expression Tree
Expression and Expression<> are basically classes that can represent the CSharp code as Data. Really? Yeah really. Unlike Func<> or Action<> Expressions are non-compiled Data about the code. Most of LINQ Providers has been built using Expressions. Let’s get started with a sample Expression and try to understand it.
Walkthrough of a sample expression
Expression can be parsed, analyzed in the program. Have you wondered how Linq to Sql works? How those Linq statements get converted to Sql? How Linq is a deffered execution? Let’s not get into complex example. Let us start with “Show me with Code” stuff.
Let’s create a simple Expression.
// A simple delegated operation that performs string join.
Func<string, string, string> StringJoin = (str1, str2) => string.Concat(str1, str2);
Now I want to parse it analyze it or may be doing some more but for that I need to treat this code as Data. Now let’s write an expression for the above lambda expression.
Expression<Func<string, string, string>> StringJoinExpr = (str1, str2) => string.Concat(str1, str2);
The Expression Tree can be visualized as with it’s major properties.
Let’s analyze our Expression according to above figure, and see what values are populated to understand the break of Expression statement
So it’s parsed like a tree with NodeType, Left, Right and Body. Which means it can be written as.
Parameters(Left) ->(Root)NodeType -> (Right)Body
Now we have the data, so one can perform operation based on its values. That’s how Linq2Sql works. It analyzes the Expression, convert the Expression Tree to SQL statements and prepare the query. Expression are major building blocks of any Linq providers.
Compile and Invoke the Expression
Unlike Func<> and Action<> expression are not compile time unit. They need to be compiled before executing the underlying instruction. So to execute the our Expression we must first compile it.
var func = StringJoinExpr.Compile();
var result = func("Smith", "Jones");
Or you can write in single statement like
var result = StringJoinExpr.Compile()("Smith", "Jones");
So, we have used Expression to represent a Lambda and it’s body. We looked into the details of how it’s represented as Expression Tree. And how to compile and invoke the code represented by Expression tree.