Using C# Expression Trees with the Real World example

Using C# Expression Trees in the Real World

In this article, I will discuss ExpressionTree. Expression tree is a compelling feature of the C#. It allows us to

  • Generate code at runtime
  • Rewrite code at runtime
  • Translate code at runtime.

Let’s understand the difference is between Func<T> and Expression<Func<T>>. with code example. Then we will write some real-world code examples with the help of the expression tree.

Lambda expression as executable code.

Func<int, bool> deleg = i => i < 5;
// Invoke the delegate and display the output.
Console.WriteLine("deleg(4) = {0}", deleg(4));

Lambda expression as data in the form of an expression tree.

Expression<Func<int, bool>> expr = i => i < 5;
// Compile the expression tree into executable code.
Func<int, bool> deleg2 = expr.Compile();
// Invoke the method and print the output.
Console.WriteLine("deleg2(4) = {0}", deleg2(4));

I hope you have understood the difference between Func and Expression<Func> with the above two examples. Func is executing code while Expression is data in the form of the expression tree.

Let’s understand this with a real-world example. Let’s suppose you want to develop an API that takes table name and columns and generate SQL select statement.

void Main()
{
	string tableName = "Customer";

	var output=GenerateSql(tableName, "name", "age");
	Console.WriteLine(output);
	
}
public string GenerateSql(string tableName, 
params string[] columns)
{
	var selectedFields = string.Join(',', columns);
	return $"SELECT {selectedFields} FROM {tableName}";
}

If you run the application, you will see the following output

SELECT name, age FROM Customer

Nothing wrong with this code, but this code is very error-prone because there is no check on the column. For example, if the developer mistypes the name as fname, the program will not complain, and it will give you the error or wrong result.

var output=GenerateSql(tableName, "fname", "age");

Better Way

Let’s write the code in a better way.

void Main()
{
	string tableName = "Customer";
	var output2=GenerateSql<Customer>(tableName,x=>x.Name,x=>x.Age,x=>x.Phone);
	Console.WriteLine(output2);
	
}
public string GenerateSql<T>(string tableName, params Expression<Func<T, object>>[] columnsName)
{
	var fields = new List<string>();

	foreach (var selector in columnsName)
	{
		var body = selector.Body;
		if (body is MemberExpression me)
		{
			fields.Add(me.Member.Name.ToLower());
		}
		else if (body is UnaryExpression ue)
		{
			 fields.Add(((MemberExpression)ue.Operand).Member.Name.ToLower());
		}
	}
	var selectedFields = string.Join(',', fields);
	return $"SELECT {selectedFields} FROM {tableName}";
}
public class Customer
{
	public string Name { get; set; }
	public int Age { get; set; }
	public int Phone { get; set; }
}

The core of the logic is this expression Expression<Func<T, object>>[] columnsName this expression will provide the data to the C# compiler.

As per the Microsoft

Expression trees represent code in a tree-like data structure. For example, each node is an expression, a method call, or a binary operation such as `x < y’.
You can compile and run code represented by expression trees. This enables dynamic modification of executable code, the execution of LINQ queries in various databases, and the creation of dynamic queries. For more information about expression trees in LINQ

See the Expression tree for the following code.

	x=>x.Name
var x = new ParameterExpression {
    Type = typeof(Customer),
    IsByRef = false,
    Name = "x"
};

new Expression<Func<Customer, object>> {
    NodeType = ExpressionType.Lambda,
    Type = typeof(Func<Customer, object>),
    Parameters = new ReadOnlyCollection<ParameterExpression> {
        x
    },
    Body = new UnaryExpression {
        NodeType = ExpressionType.Convert,
        Type = typeof(object),
        Operand = new MemberExpression {
            Type = typeof(int),
            Expression = x,
            Member = typeof(Customer).GetProperty("Age")
        }
    },
    ReturnType = typeof(object)
}
Next Post Previous Post
No Comment
Add Comment
comment url