I’m currently doing an SOA project and I have to put forward the solution architecture for many aspects of the solution. If you’ve done a bit of true SOA project (not to get into religious debate, let’s just say ‘where your architecture is oriented around services not just as a remote procedure call mechanism but where the services are first class citizen in the system’), you probably faced the problem of different entity representations and mapping between them.
Mapping, in large volume, can be tedious and if you do mapping in both directions, chances are you’ll introduce errors. A mechanism to reverse mappings would be useful. Also, when you raise exception or validation errors about a representation, it would be nice to be able to map those directly to another representation.
I knew about expression trees since the introduction of LINQ with C# 3.0. But since then, there has been some nice features using it in the .NET Framework. For instance, in ASP.NET MVC, when you do data binding, you don’t say Bind(myObject, “PropertyA”), you give it an elegant lambda expression, m => m.PropertyA. Same for Entity Framework 4.1 when doing convention overrides. Those have many advantages: they are strongly typed, hence both intellisense and the compiler will help you with the property names, it allows the manipulation of the expression (e.g. reversing a mapping) and refactoring will hit it, while a property name stored between quotes isn’t looked at by any refactoring tool.
Expression trees (ET, phoning home or not) are well documented in MSDN articles, but those never show you how to really use it. I’m going to do a series of blog entry doing just that: exploring scenarios using expression trees.
Basically, I would like to explore topics such as:
- Fetching properties with ET
- Improving declarative fetching (adding null-checks)
- Mapping two representations with ET
- Finding dependencies
- Reversing a mapping
- Reversing a partial mapping in an existing object
- Do all of that with collections & LINQ queries
- etc.
Here’s the first entry where I’ll cover some basics.
First let’s look at lambda expressions. Lambda expressions are coming from the functional programming tradition where you can express a function in a very compact way. In C#, we can view a lambda expression as the result of an evolution of delegates.
In .NET 1.x, when you needed a delegate, you had to implement a separate method:
private static void DelegateEvolution()
{
IntToInt incrementDelegate = new IntToInt(Increment);Console.WriteLine(incrementDelegate(2));
}private delegate int IntToInt(int integer);
private static int Increment(int num)
{
return num + 1;
}
This was quite verbose when you wanted to expose simple functions. .NET 2.0 brought two improvements: anonymous delegates and implicit delegate:
IntToInt incrementDelegate = new IntToInt(Increment); // .NET 1.x
IntToInt incrementDelegate2 = Increment; // .NET 2.0, no need to new the delegate
IntToInt incrementDelegate20 = delegate(int num) { return num + 1; }; // .NET 2.0
C# 3.0 brought the lambda expressions:
IntToInt incrementDelegate3 = num => num + 1; // .NET 3.0, lambda expression
A lambda expression is simply syntactic sugar to create a delegate. Underneath, it still is a delegate. We can prove that to ourselves with the following code:
IntToInt incrementDelegate3 = num => num + 1; // .NET 3.0, lambda expression
Console.WriteLine(incrementDelegate3.Method.DeclaringType);
Console.WriteLine(incrementDelegate3.Method.Name);
This will display the class where the delegate is implemented (the class where the lambda expression is defined) and a generated method name, typically containing underscores (‘_’).
Now that was useful for LINQ to objects, but when LINQ to SQL (and later LINQ to Entity) came along, just having a delegate wasn’t enough. LINQ represents where clauses, projections and other artefacts as lambda expressions. But in order to translate those expressions into SQL queries, you need more than a delegate, you need a logic representation of the lambda expression where you’ll be able to take it apart and translate it into another language (e.g. TSQL).
Enter the expression trees:
Expression<Func<int, int>> incrementExp = num => num + 1;
Here, Func<int, int> is a .NET Framework defined generic delegate, taking an int, returning an int. We could take the expression tree and compile it into a delegate.
Expression<Func<int, int>> incrementExp = num => num + 1;
Func<int, int> increment = incrementExp.Compile();Console.WriteLine(increment(2));
Console.WriteLine(incrementExp);
In the last line, we also print-out the expression tree which lays out the textual representation of it (num => num+1).
But if we do not compile it, we can look at the inside of the expression tree. Now this becomes quickly tedious as we’ll see with this very simple one.
var parameters = incrementExp.Parameters; // Represents the parameters (i.e. num)
var body = incrementExp.Body as BinaryExpression; // Represents num + 1
var bodyNodeType = body.NodeType; // Represents the addition operation
var left = body.Left as ParameterExpression; // Represents ‘num’
var right = body.Right as ConstantExpression; // Represents ‘1’Console.WriteLine("Operation: " + bodyNodeType);
Console.WriteLine("Left: " + left.Name);
Console.WriteLine("Right: " + right.Value);
We can also create expressions from scratch. For instance, we could construct a similar lambda with the following code:
var num = Expression.Variable(typeof(int), "num"); // num variable of type int
var constant = Expression.Constant(2); // constant ‘2’
var addition = Expression.Add(num, constant); // num + 2
var lambda = Expression.Lambda<Func<int, int>>(addition, num); // num => num + 2Console.WriteLine(lambda);
Console.WriteLine(lambda.Compile()(2));
This is extremely powerful, because we basically create code semantically but this code is compiled into MSIL and runs as efficiently as any other code you could do in Visual Studio.
Expression trees are read-only: you can’t modify them. There is also a mechanism to create a modified version though, using the visitor pattern (Yes, you’ve read correctly, a GOF pattern is mentioned explicitly in the .NET Fx: it acknowledges its existence!).
For instance, let’s say we would like to take the lambda num => num + 1 and change it into num => num + 5. We first need a visitor:
private class ConstantModifier : ExpressionVisitor
{
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value is int && (int)node.Value == 1)
{
return Expression.Constant(5);
}
else
{
return node;
}
}
}
The visitor is creating new expressions if needed otherwise return original expressions. This visitor only visits constant expressions, but there are virtual methods for each type of expressions. We can use the visitor to modify an expression tree:
Expression<Func<int, int>> incrementExp = num => num + 1;
var modifier = new ConstantModifier();
var modifiedIncrementExp = modifier.Visit(incrementExp) as Expression<Func<int, int>>;Console.WriteLine(modifiedIncrementExp);
Console.WriteLine(modifiedIncrementExp.Compile()(1));
So far we’ve looked at lambda expression representing functions computing something at the input and returning an output. A lambda expression, in .NET, can also represents an action. Interestingly enough, there are limitations on how we can express actions when assigning expressions. For instance, we can’t assign a property within an expression but we can create the expression doing that in code.
Let’s create an expression taking an integer and setting it to the exit code of the application:
var code = Expression.Variable(typeof(int), "code"); // Input
var exitCodeProperty =
Expression.Property(null, typeof(Environment), "ExitCode"); // Environment.ExitCode
var assignation = Expression.Assign(exitCodeProperty, code); // Environment.ExitCode=code
var assignLambda =Expression.Lambda<Action<int>>(assignation, code); // The action wrapping it
Console.WriteLine(assignLambda);
assignLambda.Compile()(10);
Console.WriteLine(Environment.ExitCode);
In the next blog entries of this series, I’ll explore specific scenarios.
2 thoughts on “Expression Trees: Part 1 – Basics”