C sharp - Expression Trees in C#
Expression Trees allow you to represent code as data.
Instead of executing a method immediately, you can store its structure in a tree format and inspect, modify, or execute it later.
They are mainly used in:
-
LINQ providers (like Entity Framework)
-
Dynamic query generation
-
Rule engines
-
Compilers and code analyzers
1. Normal Code vs Expression Tree
Normal Lambda (Compiled and Executed)
Func<int, int> square = x => x * x;
Console.WriteLine(square(5)); // 25
Here:
-
Code is compiled into IL
-
It executes directly
Expression Tree Version
using System.Linq.Expressions;
Expression<Func<int, int>> squareExpr = x => x * x;
Here:
-
The lambda is not executed
-
It is converted into a tree structure
2. What Does the Tree Look Like?
For:
x => x * x
The structure is:
Lambda
└── Multiply
├── Parameter (x)
└── Parameter (x)
Each part is represented by an object:
-
ParameterExpression
-
BinaryExpression
-
LambdaExpression
3. Compiling an Expression Tree
To execute it:
var compiled = squareExpr.Compile();
Console.WriteLine(compiled(5)); // 25
Important:
-
Expression Tree → needs
.Compile()to execute -
Normal Func → executes directly
4. Why Expression Trees Are Important
They allow inspection of code logic.
Example:
Entity Framework uses them to translate C# code into SQL.
var result = db.Users.Where(u => u.Age > 18);
The lambda u => u.Age > 18 becomes an Expression Tree.
EF reads it and converts it into:
SELECT * FROM Users WHERE Age > 18
Without expression trees, this translation is impossible.
5. Building Expression Trees Manually
You can construct them programmatically.
ParameterExpression param = Expression.Parameter(typeof(int), "x");
BinaryExpression body = Expression.Multiply(param, param);
Expression<Func<int, int>> lambda =
Expression.Lambda<Func<int, int>>(body, param);
var compiled = lambda.Compile();
Console.WriteLine(compiled(4)); // 16
This is how dynamic query engines work internally.
6. Common Expression Types
| Type | Purpose |
|---|---|
| ParameterExpression | Represents variable |
| ConstantExpression | Represents constant value |
| BinaryExpression | +, -, *, / |
| MethodCallExpression | Calling methods |
| LambdaExpression | Full lambda structure |
7. Expression Trees vs Delegates
| Delegate (Func) | Expression Tree |
|---|---|
| Executes directly | Stores structure |
| Cannot inspect logic | Can inspect and modify |
| Faster | Slightly slower |
| Used for runtime execution | Used for dynamic analysis |
8. Limitations
Expression Trees:
-
Cannot represent all C# syntax
-
No loops like
for,while -
Limited statement support
-
Designed mainly for expressions, not full methods
9. Real-World Uses
-
Entity Framework
-
LINQ Providers
-
Dynamic filtering systems
-
Code generation tools
-
Rule engines
-
ORMs
10. Advanced Concept: Expression Visitors
C# provides ExpressionVisitor class.
It allows:
-
Traversing
-
Modifying
-
Rewriting expression trees
Example use case:
Automatically modify all x > 18 to x > 21.
This is powerful for:
-
Security filters
-
Multi-tenant applications
-
Query rewriting