Skip to contentSkip to author details

C# Introduction to Expression Trees

Written by Jeff Tyler

Recently I was in a situation where I needed to write my own expression trees to be consumed by Entity Framework. I thought that it would be a good opportunity to pass what I learned along.

Along the way I came up with three realizations that helped me understand what I was doing.

When dealing with Expression Trees you are dynamically building lamda expressions

The power of an Expression Tree is not in it's ability to be used in C# code but in it's ability to write code for another system.

The questions that you are asking when dealing with expression trees are different.

When you write person.Name == "Jeff" you asking if the two are equals. With a lamda your asking what the result of a method is.
With expression trees you are asking how do I build this Lamda in code. So you have to create the parameters and comparison steps separately.

When you consume an expression. You are less concerned with the result of the expression and more concerned with the steps required to get to the end result.

So an explanation of what an expression tree is. An expression tree is used so that you can interpret the code and generate something else. Entity Framework takes an expression tree and uses it to build SQL.
So here is how I finally get my head wrapped around them.

    var person = new Person(){ Name = "Jeff"};
    var isJeff = person.Name == "Jeff";

This is regular code. It is compiled down and when it gets to this line it creates a new person and then sets isJeff to true. This can be used in if statements to change the flow.

var person = new Person { Name = "Jeff" };  
            Func<Person, bool> isJeff = (p) => p.Name == "Jeff";
            var list = new List<Person> { person };
            var jeffs = list.Where(isJeff);
           // calling invoke makes it behave like a regular method.
           var result = isJeff.Invoke(person);

This is a lamda. It creates a function delegate that can be used on any Person to see if they are a Jeff. This can be passed along to LINQ to be used as a filter of a list. This code behaves like a method when it is invoked.

var person = new Person { Name = "Jeff" };  
var param = Expression.Parameter(typeof(Person));  
var property = Expression.Property(param,nameof(Person.Name));  
var constant = Expression.Constant("Jeff");  
var equals = Expression.Equal(property, constant);  

The equals expression gives us three important pieces of information. By knowing it's type we know how to compare it. It is an Equal Expression so we know that it is the same as doing an ==. With equals.Left we can get the property access from the param. It will read param_0.Name.
With equals.right we can see the constant that we added. Which will be "Jeff".

Let's say that we knew an identical object existed in a JavaScript application. we could take this and write something like this

Console.WriteLine(equals.Left + "===" + equals.Right);  

This code would wind up looking like this
param0.Name === "Jeff";
if you happened to have a param
0 variable this would validate it. Not very useful at the moment but it does demonstrate one important thing.

Were going to take it one more step and see if we can't get a more useful condition check.

// this code will only handle a single condition. 
public static string CreateJavaScriptMethod(Expression<Func<Person, bool>> expression)  
        {
            var jsCode = $"function validation({expression.Parameters[0]}) {{";
            var body = expression.Body as BinaryExpression;
            var comparer = "";
            switch (body.NodeType)
            {
                case ExpressionType.Equal:
                    {
                        comparer = "===";
                        break;
                    }
                case ExpressionType.NotEqual:
                    {
                        comparer = "!==";
                        break;
                    }
                case ExpressionType.GreaterThan:
                    {
                        comparer = ">";
                        break;
                    }
                case ExpressionType.LessThan:
                    {
                        comparer = "<";
                        break;
                    }
            }
            jsCode += $"return {body.Left} {comparer} {body.Right}";

            jsCode += "}";

            return jsCode;
        }

This is a method created to handle a simple validation scenario. You write some validation in C# and it generates a javascript method for validation.
The method takes Expression function.
expression.paramters holds all of the paramters for the function. expression.Body is a binary expression. It has a Left, a Right, and it's type will tell you how it is comparing the two values. The switch statement checks the expression type and creates the correct JavaScript equality check.

So now we are going to use the method.
This is the normal use of it.

var script = CreateJavaScriptMethod(p => p.Name == "Jeff");  

This is just a plain old lamda expression that does the same comparison as the one we built. Like you would use for LINQ or Enity Framework. Only this one will give you a JavaScript method.

We can make it a bit more dynamic by building the expression using the expression trees.

Expression<Func<Person, bool>> expression = Expression.Lambda<Func<Person, bool>>(equals, param);

CreateJavaScriptMethod(expression);  

After calling Expression.Lamda on the expression that we created in the beginning it then can be used exactly like the lamda expression.