C# Expression Trees Cookbook

Expression trees are a powerful feature of C# that allow you to manipulate code as data. They can be used for various purposes, such as creating dynamic queries, implementing custom LINQ providers, or performing runtime compilation. In this post, I will share some interesting techniques I had experienced when working with expression trees. If you’d like to add, please comment below.

If you want to create code on the fly, expression trees are a cool way to do it. They are like mini-programs that you can build and run in C#. They take care of a lot of details for you, so you don’t have to worry about things like CIL or MSIL. They can also make your code faster and more efficient than using reflection or dynamic methods. Expression trees are awesome!

Coding with expression trees is a fascinating and fun way to explore the power of programming languages. Expression trees are data structures that represent code as a tree of nodes, where each node can be an operator, a literal value, a variable or a function call. By creating expression trees, you can manipulate code as data and dynamically generate and execute new code at runtime. This means that you are writing an algorithm to create expression trees on one hand, and creating an algorithm to run something else on the other hand. Both at the same time! How cool is that? 😎

Interesting Facts

  • Result of an expression is the last expression in the block. This means that you can write concise and elegant code that returns a value without using a return statement. For example, you can write a lambda expression like this: (x,y) => { x++; y--; x + y; } and it will return the sum of x and y after incrementing x and decrementing y.
  • if/then/else are not expressions, meaning they return void type. This means that you cannot use them in places where an expression is expected, such as in a ternary operator or a switch expression. For example, you cannot write something like this: var result = condition ? if (true) { doSomething(); } else { doSomethingElse(); } : default;. You have to use an expression instead of an if/then/else statement.
  • If you need an expression but can’t think of one yet, use Expression.Empty(). This is a handy method that returns an empty expression tree node. You can use it as a placeholder for an expression until you figure out what you want to write. For example, you can write something like this: var expr = Expression.Lambda(Expression.Empty(), parameter); and then later assign a body to the lambda expression using expr.Body = ...;.

Arrays

Create New

int[] ar = new int[3] translates to:

var arVar = Expression.Variable(typeof(int[]), "ar");

var x = Expression.Block(new[] { arVar },
    Expression.Assign(arVar, Expression.NewArrayBounds(typeof(int), Expression.Constant(3)))
);

Access

Accessing ar[2] translates to Expression.ArrayAccess(arVar, Expression.Constant(2)).

Properties

Having a class

class Entity {
    public int Id { get; set; }
    public int? NullableInt { get; set; }
}

Assign Value

If an instance of Entity is cVar then cVar.Id = 3 translates to:

Expression.Assign(Expression.Property(cVar, "Id"), Expression.Constant(3));

and cVar.NullableInt = 3 translates to:

Expression.Assign(Expression.Property(cVar, "NullableInt"), Expression.Convert(Expression.Constant(3), typeof(int?)));

Conditions

If/Then/Else

if(xVar < yVar) {
    // on true
} else {
    // on false
}

translates to

Expression.IfThenElse(
    Expression.LessThan(xVar, yVar),

	// on true
    Expression.Empty(),
    
    // on false
    Expression.Empty());

If you are a fan of functional programming, you might be frustrated by the limitations of the IfThenElse construct in C#. The problem with IfThenElse is that it’s actually a statement (return type is void) and not an expression. Meaning if you need to return something from it, that needs to be wrapped in a block. For instance, to return a boolean flag:

bool flag = false;
if (condition) {
    flag = true;
} else {
    flag = false;
}

Or in expression syntax:

 ParameterExpression flag = Expression.Variable(typeof(bool), "successFlag");
    return Expression.Block(
        new[] { flag },
        Expression.IfThenElse(
            Expression.LessThan(xVar, yVar),

            Expression.Block(

                // do something
                Expression.Empty(),
                // flag = true
                Expression.Assign(flag, Expression.Constant(true))),

            // flag = false
            Expression.Assign(flag, Expression.Constant(false))),

        // return flag
        flag);

This is verbose and cumbersome compared to the ternary operator: bool flag = condition ? true : false;.

Ternary Null Check

I.e. ? : operator.

x == null ? null : x.y; translates to:

Expression.Condition(Expression.Equal(x, Expression.Constant(null)),
                     Expression.Convert(Expression.Constant(null), childType),   // cast null to childType as argument types must match
                    Expression.Property(x, "y"));

One of the coolest features of Condition is that it can return a value! Unlike IfThenElse, which only executes a block of code based on a condition and returns nothing (void), Condition can evaluate an expression and return either null or the result of the expression. For example, if you write Condition(x != null, x.y), it will return either null if x is null, or x.y if x is not null. This way, you can use Condition in places where you need a value, such as assignments, arguments or returns. Isn’t that awesome?

Loops

If you want to create loops with expression trees, you must use Expression.Loop. This method creates an expression that represents an infinite loop. That’s right, infinite! There is no other way to create loops with expression trees. You might wonder how to exit an infinite loop. Well, you can use Expression.Break or Expression.Return to jump out of the loop at any point. Isn’t that cool? Expression trees are a powerful way to represent code as data and manipulate it dynamically. So go ahead and try Expression.Loop and see what amazing things you can do with it!

Simulating foreach

Let’s simulate the following:

foreach(var element in collection) {
    // do something
}

as expression trees. collection implements IEnumerable<T> and we’ll refer to T as elementType in this code.

Type enumeratorGenericType = typeof(IEnumerator<>).MakeGenericType(elementType);
Type enumerableGenericType = typeof(IEnumerable<>).MakeGenericType(elementType);

ParameterExpression enumeratorVar = Expression.Variable(enumeratorGenericType, "enumerator");
MethodCallExpression getEnumeratorCall = Expression.Call(classesParam,
    enumerableGenericType.GetMethod(nameof(IEnumerable.GetEnumerator))!);
MethodCallExpression moveNextCall = Expression.Call(enumeratorVar,
    typeof(IEnumerator).GetMethod(nameof(IEnumerator.MoveNext))!);
LabelTarget loopBreakLabel = Expression.Label("loopBreak");

 LoopExpression loop = Expression.Loop(
    Expression.IfThenElse(

        // test
        Expression.Equal(moveNextCall, Expression.Constant(true)),

        // if true
        Expression.Block(
            // do something...
        ),

        // if false
        Expression.Break(loopBreakLabel)
        ), loopBreakLabel);

return Expression.Block(
    new[] { enumeratorVar, classElementVar },

    // get enumerator from class collection
    Expression.Assign(enumeratorVar, getEnumeratorCall),

    // loop over classes
    loop);

Lists

Create new generic list

new List<int> translates to

Expression.New(typeof(List<int>));

new List<T> translates to

Expression.New(typeof(List<>).MakeGenericType(typeof(T)));

Declare, Create and Assign

var list = new List<int>();

translates to:

Type listType = typeof(List<int>);
var listVar = Expression.Variable(listType, "list");
var result = Expression.Assign(listVar, Expression.New(listType));

Assign null to List variable

If you are trying to assign null to list variable in the following way:

Expression.Assign(listVar, Expression.Constant(null));

it won’t work and will fail with an exception:

System.ArgumentException : Expression of type 'System.Object' cannot be used for constructor parameter of type 'System.Collections.Generic.List`1[System.Int32]' (Parameter 'arguments[2]')

The trick is to convert null to the list type before assigning:

Expression.Assign(listVar, Expression.Convert(Expression.Constant(null), typeof(List<int>)));

which is equivalent to the following C# code:

listVar = (List<int>)null;

Get List element by Index

I.e. elementVar = listVar[idxVar] will translate to:

Expression.Assign(elementVar, Expression.Property(listVar, "Item", idxVar));

because accessing an indexer in the collection is equivalent to accessing it’s property Item.

Dictionaries (maps)

Accessing

Accessing a dictionary by key is nothing more than calling it’s Item indexed property.

var  dict = new Dictionary<string, int> {
    { "One", 1 },
    { "Two", 2 }
};

ParameterExpression param = Expression.Parameter(typeof(Dictionary<string, int>), "dict");
ParameterExpression key = Expression.Constant("One");

// equivalent to dic["One"]:
IndexExpression indexExpression = Expression.Property(param, "Item", key);

Exceptions

Throw NotImplementedException when all the parameters are known before compiling:

private static Expression ThrowNotImplementedException(string message) {
    return Expression.Throw(Expression.Constant(new NotImplementedException(message)));
}

Tricks

View Expression in Release Mode

If you are a fan of Visual Studio’s DebugView property, you know how useful it is to see the pseudo code of an expression without having to compile it. But what if you want to use this feature in Release Mode? Unfortunately, DebugView is an internal property that is only accessible in Debug Mode. However, there is a workaround! You can use this helper extension method to get the DebugView value of any expression in Release Mode. This way, you can still enjoy the benefits of DebugView without sacrificing performance or security. Isn’t that awesome?

public static string GetPseudoCode(this Expression expression) {
    PropertyInfo? propertyInfo = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic);
    if(propertyInfo == null)
        return string.Empty;

    return (string)propertyInfo.GetValue(expression)!;
}

Debugging

If you love expression trees as much as I do, you might wonder how to debug them effectively. Well, I have some good news for you! You don’t need to rely on the boring DebugView property or some external tools to inspect your expression trees. You can create your own pseudo breakpoint by calling a method from your expression tree into one of your classes. How cool is that?

Let me show you how I do it with a static method in my class that generates expression trees:

#if DEBUG
    private static void InspectCurrentValues(int dataIdx, int dlIdx, int rlIdx) {
        Console.WriteLine($"iteration: D: {dataIdx}, DL: {dlIdx}, RL: {rlIdx}", dataIdx, dlIdx, rlIdx);
    }
#endif

Then, in the expression tree itself, I can call this method:

#if DEBUG
    Expression.Call(GetType().GetMethod(nameof(InspectCurrentValues),
		BindingFlags.NonPublic | BindingFlags.Static)!, _dataIdxVar, _dlIdxVar, _rlIdxVar),
#endif

Breakpoint can be set and will be hit inside the InspectCurrentValues method.

Tools

  1. ReadableExpressions.Visualizers for Visual Studio transforms expression tree to a really nice, C#-like view. Compare DebugView to the output of this visualiser:

image-20230309152646639


To contact me, send an email anytime or leave a comment below.