# Expression Trees

Course: [C# Advanced](https://www.devtutorials.ai/learn/advanced-csharp) · Section: Reflection and Metadata
Source: https://www.devtutorials.ai/learn/advanced-csharp/reflection-and-attributes/expression-trees

> Store code as data: Expression and lambda trees, building nodes by hand, compiling and executing, ExpressionVisitor, dynamic queries, IQueryable and how ORMs translate to SQL.

## Introduction to Expression Trees

Think about two ways to share a recipe.

You can **cook the dish** and hand over the plate. The other person can eat it, but they cannot see how it was made.

Or you can **write the recipe down**. Now the other person can read each step, change an ingredient, translate it into another language, and then cook it.

A normal lambda like `x => x > 5` is the plate. It is already compiled and ready to run. No one can look inside to see how it works.

An **expression tree** is the written recipe. It stores the **same lambda as data**: a tree of small pieces that explains "take the input `x`, take the number `5`, compare them with greater-than." Your code can read that tree, change it, turn it into SQL, or compile it and run it.

**In simple words:** an expression tree is code saved as data, so other code can read and work with it.

**Easy Way to Remember:** a **delegate is the cooked dish**. An **expression tree is the recipe**.

## What You Will Learn

In this lesson, you will learn:

1. What an `Expression` is and how it works differently from a delegate.
2. How the compiler turns a lambda into an expression tree.
3. How to build expression trees yourself.
4. The main kinds of expression pieces (called nodes).
5. How to compile and run an expression tree.
6. How to read and change trees with `ExpressionVisitor`.
7. How to build searches and filters at runtime.
8. How LINQ and databases like Entity Framework use expression trees.

All runnable examples on this page run in your browser. Compiling expression trees works here too. Examples that need a real database, like Entity Framework Core, are shown as plain code. The runnable examples use in-memory data instead.

## Start With a Working Example

Press **Run**.

```csharp runnable title="The same lambda as a delegate and as data"
using System;
using System.Linq.Expressions;

Func<int, bool> asCode = x => x > 5;
Expression<Func<int, bool>> asData = x => x > 5;

Console.WriteLine($"Delegate result: {asCode(8)}");
Console.WriteLine($"Delegate as text: {asCode}");

Console.WriteLine($"Tree as text:    {asData}");
Console.WriteLine($"Tree body:       {asData.Body}");
Console.WriteLine($"Body node type:  {asData.Body.NodeType}");

var compare = (BinaryExpression)asData.Body;
Console.WriteLine($"Left side:       {compare.Left}");
Console.WriteLine($"Right side:      {compare.Right}");
```

Both lines have the same lambda: `x => x > 5`. The only difference is the declared type.

- As a `Func<int, bool>`, it is compiled code. Printing it gives you no useful information.
- As an `Expression<Func<int, bool>>`, it is a tree. You can print it and look inside: left side, right side, and operator.

### Try This

Change both lambdas to `x => x % 2 == 0` and run again. Look at the `Body node type` line. It changes from `GreaterThan` to `Equal`.

## Expression

`System.Linq.Expressions.Expression` is the **base class** for every piece of a tree. Each piece is called a **node**.

Every node has two key parts:

- **`NodeType`** tells you what the node does: `Add`, `Constant`, `Parameter`, `Call`, `GreaterThan` and so on.
- **`Type`** tells you what .NET type the node produces when it runs: `int`, `bool`, `string`.

Nodes hold other nodes inside. A `BinaryExpression` like `a + b` holds a `Left` node and a `Right` node. That is why it is called a **tree**: one top node with branches going down to the leaves.

```csharp runnable title="Walk down the tree"
using System;
using System.Linq.Expressions;

Expression<Func<int, int, int>> price = (qty, rate) => qty * rate + 50;

Show(price.Body, 0);

static void Show(Expression node, int depth)
{
    string indent = new string(' ', depth * 2);
    Console.WriteLine($"{indent}{node.NodeType} ({node.Type.Name}): {node}");

    if (node is BinaryExpression b)
    {
        Show(b.Left, depth + 1);
        Show(b.Right, depth + 1);
    }
}
```

The top node is `Add`. Its left branch is the `Multiply`. Its right branch is the number `50`. The bottom pieces are the inputs `qty` and `rate`, and the number.

```text
            Add
          /     \
     Multiply    50
      /    \
    qty    rate
```

## Lambda Expressions

The easiest way to get an expression tree is to let the **compiler** build it.

When you save a lambda to a variable of type **`Expression<TDelegate>`**, the compiler does not turn the lambda into code. Instead, it writes code that **builds the tree**.

The top of the tree is a **`LambdaExpression`**. It has:

- **`Parameters`**: what the lambda takes as input,
- **`Body`**: the expression after the `=>`,
- **`ReturnType`**: what the lambda gives back.

```csharp runnable title="Inside a LambdaExpression"
using System;
using System.Linq.Expressions;

Expression<Func<string, int, bool>> rule = (name, age) => name.Length > 2 && age >= 18;

Console.WriteLine($"Whole lambda: {rule}");
Console.WriteLine($"Returns:      {rule.ReturnType.Name}");

foreach (ParameterExpression p in rule.Parameters)
    Console.WriteLine($"Parameter:    {p.Name} : {p.Type.Name}");

Console.WriteLine($"Body:         {rule.Body}");
Console.WriteLine($"Body type:    {rule.Body.NodeType}");
```

### What the Compiler Cannot Convert

Only **expression lambdas** (a single expression after `=>`) can become trees. A **statement lambda** with braces cannot.

```text
Expression<Func<int, int>> ok = x => x * 2;

Expression<Func<int, int>> bad = x => { return x * 2; };
// error CS0834: A lambda expression with a statement body
// cannot be converted to an expression tree
```

A few other things are not allowed either, like `await`, assignments with `=`, and some newer syntax. The compiler tells you with an error when you use one.

## Building Expression Trees

You can also build a tree **by hand**, using the static factory methods on the `Expression` class. This is how you create code whose shape you only learn while the program runs.

Each factory method makes one node:

| Method | Makes | Like writing |
|---|---|---|
| `Expression.Parameter(typeof(int), "x")` | An input | `x` |
| `Expression.Constant(10)` | A fixed number | `10` |
| `Expression.Add(a, b)` | Addition | `a + b` |
| `Expression.GreaterThan(a, b)` | Comparison | `a > b` |
| `Expression.Property(obj, "Name")` | Property read | `obj.Name` |
| `Expression.Call(obj, method, args)` | Method call | `obj.Method(args)` |
| `Expression.Lambda<T>(body, params)` | The full lambda | `x => body` |

You build from the **leaves up**: first the inputs and numbers, then the operators that combine them, and finally the lambda.

```csharp runnable title="Build x => x * 2 + 1 by hand"
using System;
using System.Linq.Expressions;

// 1. Leaves
ParameterExpression x = Expression.Parameter(typeof(int), "x");
ConstantExpression two = Expression.Constant(2);
ConstantExpression one = Expression.Constant(1);

// 2. Branches
BinaryExpression times = Expression.Multiply(x, two);
BinaryExpression plus = Expression.Add(times, one);

// 3. Root
Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(plus, x);

Console.WriteLine(lambda);
Func<int, int> run = lambda.Compile();
Console.WriteLine($"f(5) = {run(5)}");
```

The tree you build by hand prints just like a lambda you typed: `x => ((x * 2) + 1)`.

### Building With Properties and Method Calls

Real code works with objects. `Expression.Property` reads a property. `Expression.Call` calls a method.

```csharp runnable title="Build a StartsWith filter by hand"
using System;
using System.Linq.Expressions;

ParameterExpression p = Expression.Parameter(typeof(Person), "p");
MemberExpression name = Expression.Property(p, nameof(Person.Name));
var startsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) })!;
MethodCallExpression call = Expression.Call(name, startsWith, Expression.Constant("A"));

var filter = Expression.Lambda<Func<Person, bool>>(call, p);
Console.WriteLine(filter);

var test = filter.Compile();
Console.WriteLine($"Asha: {test(new Person("Asha"))}");
Console.WriteLine($"Ravi: {test(new Person("Ravi"))}");

record Person(string Name);
```

`Expression.Call` needs a `MethodInfo`, so this is where reflection from lesson 13 comes back. Expression trees and reflection work together often.

Hand-built trees are checked when you **build** them, not when you write them. A wrong type, like adding an `int` to a `string`, throws an `InvalidOperationException` or `ArgumentException` from the factory method while the program runs. Build trees step by step and print them as you go.

## Expression Nodes

There are about 85 node types, but a small number cover most real code.

| Node class | `NodeType` examples | Represents |
|---|---|---|
| `ParameterExpression` | `Parameter` | An input, like `x` |
| `ConstantExpression` | `Constant` | A fixed value, like `5` or `"Pune"` |
| `BinaryExpression` | `Add`, `Equal`, `AndAlso`, `GreaterThan` | Two things and an operator |
| `UnaryExpression` | `Not`, `Negate`, `Convert` | One thing |
| `MemberExpression` | `MemberAccess` | A property or field, like `p.Age` |
| `MethodCallExpression` | `Call` | A method call |
| `ConditionalExpression` | `Conditional` | `test ? a : b` |
| `NewExpression` | `New` | `new Point(1, 2)` |
| `LambdaExpression` | `Lambda` | The full lambda |

You check what kind a node is with **pattern matching**, like in the next example.

```csharp runnable title="Describe every node in a tree"
using System;
using System.Linq.Expressions;

Expression<Func<Order, string>> label =
    o => o.Total > 1000 ? "Big: " + o.Customer.ToUpper() : "Small";

Describe(label.Body, 0);

static void Describe(Expression node, int depth)
{
    string pad = new string(' ', depth * 2);
    switch (node)
    {
        case ConditionalExpression c:
            Console.WriteLine($"{pad}Conditional");
            Describe(c.Test, depth + 1);
            Describe(c.IfTrue, depth + 1);
            Describe(c.IfFalse, depth + 1);
            break;
        case BinaryExpression b:
            Console.WriteLine($"{pad}Binary {b.NodeType}");
            Describe(b.Left, depth + 1);
            Describe(b.Right, depth + 1);
            break;
        case MethodCallExpression m:
            Console.WriteLine($"{pad}Call {m.Method.Name}");
            if (m.Object != null) Describe(m.Object, depth + 1);
            break;
        case MemberExpression m:
            Console.WriteLine($"{pad}Member {m.Member.Name}");
            break;
        case ConstantExpression k:
            Console.WriteLine($"{pad}Constant {k.Value}");
            break;
        default:
            Console.WriteLine($"{pad}{node.NodeType}");
            break;
    }
}

class Order
{
    public decimal Total { get; set; }
    public string Customer { get; set; } = "";
}
```

Notice the `1000` constant. It shows as `1000` even though `Total` is a `decimal`, because the compiler stored it as a `decimal` constant. Trees keep the exact types the compiler used.

## Compiling Expressions

A tree is data. To **run** it, you must turn it into a delegate. That is what **`Compile()`** does.

`Compile()` reads the tree and makes real code that can run. It gives back a delegate with the same type as the lambda: an `Expression<Func<int, int>>` compiles to a `Func<int, int>`.

```csharp runnable title="Compile a tree into a delegate"
using System;
using System.Linq.Expressions;

Expression<Func<decimal, decimal, decimal>> withTax = (price, rate) => price + price * rate / 100;

Func<decimal, decimal, decimal> calculate = withTax.Compile();

Console.WriteLine(withTax);
Console.WriteLine($"Rs. 1000 at 18% = {calculate(1000m, 18m)}");
Console.WriteLine($"Rs. 250 at 5%   = {calculate(250m, 5m)}");
```

`Compile()` is **slow**: it makes new code every time you call it. Compile a tree **one time**, keep the delegate in a field or dictionary, and call the delegate as many times as you want. Calling the delegate is as fast as calling a normal method.

This is the expression-tree speed boost promised in the reflection lesson. You can build a fast property reader for any type and property name:

```csharp runnable title="A fast getter built from a property name"
using System;
using System.Linq.Expressions;

Func<object, object?> getter = MakeGetter(typeof(Book), "Pages");

var books = new[] { new Book { Title = "Godan", Pages = 312 }, new Book { Title = "Malgudi Days", Pages = 256 } };
foreach (var book in books)
    Console.WriteLine($"{book.Title}: {getter(book)} pages");

static Func<object, object?> MakeGetter(Type type, string propertyName)
{
    // (object obj) => (object)((Book)obj).Pages
    ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
    UnaryExpression cast = Expression.Convert(obj, type);
    MemberExpression property = Expression.Property(cast, propertyName);
    UnaryExpression boxed = Expression.Convert(property, typeof(object));
    return Expression.Lambda<Func<object, object?>>(boxed, obj).Compile();
}

class Book
{
    public string Title { get; set; } = "";
    public int Pages { get; set; }
}
```

Serializers and object mappers use this exact trick. They use reflection **once** to find properties, build a reader tree for each one, compile it, and save the delegates.

## Executing Expressions

After you compile, you run the delegate like any other method: `calculate(1000m, 18m)`.

There are two other ways to run a tree:

- **`DynamicInvoke`** on a `LambdaExpression` when you do not know its delegate type when you build. It takes an `object[]` and is slower.
- **Expression blocks** let one tree hold several steps, variables and loops. You can only build them by hand.

```csharp runnable title="Run a tree you only know as LambdaExpression"
using System;
using System.Linq.Expressions;

LambdaExpression[] formulas =
{
    (Expression<Func<int, int>>)(n => n * n),
    (Expression<Func<int, int, int>>)((a, b) => a * b + 1),
};

foreach (LambdaExpression formula in formulas)
{
    Delegate run = formula.Compile();
    object?[] inputs = formula.Parameters.Count == 1 ? new object?[] { 7 } : new object?[] { 3, 4 };
    Console.WriteLine($"{formula} with ({string.Join(", ", inputs)}) = {run.DynamicInvoke(inputs)}");
}
```

### Expression Blocks

A **`BlockExpression`** runs several expressions one after another, like statements inside braces. It can declare temporary variables. The value of the block is what its last expression gives.

```csharp runnable title="A hand-built block with a temporary variable"
using System;
using System.Linq.Expressions;

// int Discount(int price) { int cut = price / 10; Console.WriteLine(cut); return price - cut; }
ParameterExpression price = Expression.Parameter(typeof(int), "price");
ParameterExpression cut = Expression.Variable(typeof(int), "cut");
var writeLine = typeof(Console).GetMethod("WriteLine", new[] { typeof(int) })!;

BlockExpression body = Expression.Block(
    new[] { cut },
    Expression.Assign(cut, Expression.Divide(price, Expression.Constant(10))),
    Expression.Call(writeLine, cut),
    Expression.Subtract(price, cut));

var discount = Expression.Lambda<Func<int, int>>(body, price).Compile();
Console.WriteLine($"Final price: {discount(850)}");
```

## Expression Visitors

To **read** or **change** a whole tree, you visit every node. Writing that walk by hand for 85 node types is a lot of work.

**`ExpressionVisitor`** does the walk for you. You inherit from it and override only the `Visit...` methods for the nodes you care about:

- `VisitBinary` for `+`, `>`, `&&` and others,
- `VisitMember` for property reads,
- `VisitConstant` for numbers,
- `VisitParameter` for inputs,
- `VisitMethodCall` for method calls.

### Reading a Tree

This visitor collects every property name a lambda reads.

```csharp runnable title="Find the properties a lambda reads"
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

Expression<Func<Employee, bool>> rule = e => e.Salary > 50000 && e.City == "Pune" || e.Years > 10;

var finder = new PropertyFinder();
finder.Visit(rule);
Console.WriteLine($"Uses: {string.Join(", ", finder.Names)}");

class PropertyFinder : ExpressionVisitor
{
    public List<string> Names { get; } = new();

    protected override Expression VisitMember(MemberExpression node)
    {
        Names.Add(node.Member.Name);
        return base.VisitMember(node);   // keep walking into child nodes
    }
}

class Employee
{
    public decimal Salary { get; set; }
    public string City { get; set; } = "";
    public int Years { get; set; }
}
```

### Rewriting a Tree

Expression trees cannot be changed: you cannot edit a node. A visitor gives back a **new** node instead. `ExpressionVisitor` rebuilds the tree around it.

This visitor swaps every `+` for `-`.

```csharp runnable title="Rewrite + into -"
using System;
using System.Linq.Expressions;

Expression<Func<int, int, int>> original = (a, b) => a + b * 2 + 10;

var flipped = (Expression<Func<int, int, int>>)new PlusToMinus().Visit(original);

Console.WriteLine($"Original: {original}  -> {original.Compile()(5, 3)}");
Console.WriteLine($"Rewritten: {flipped}  -> {flipped.Compile()(5, 3)}");

class PlusToMinus : ExpressionVisitor
{
    protected override Expression VisitBinary(BinaryExpression node)
    {
        Expression left = Visit(node.Left);
        Expression right = Visit(node.Right);

        return node.NodeType == ExpressionType.Add
            ? Expression.Subtract(left, right)
            : node.Update(left, node.Conversion, right);
    }
}
```

The original tree stays the same. The visitor made a second, different tree.

## Dynamic Query Generation

Here is the most useful real-world use of expression trees: **building a filter while the program runs** based on what a user picks.

Imagine a search page. The user picks a field, an operator and a value. You do not know what they will pick, so you cannot write the lambda ahead of time. You build it instead.

```csharp runnable title="Build a filter from user choices"
using System;
using System.Linq;
using System.Linq.Expressions;

var products = new[]
{
    new Product("Kettle", "Kitchen", 1299m),
    new Product("Mixer", "Kitchen", 3499m),
    new Product("Lamp", "Home", 899m),
    new Product("Fan", "Home", 2499m),
};

Run("Category", "==", "Kitchen");
Run("Price", ">", 1000m);
Run("Price", "<=", 899m);

void Run(string field, string op, object value)
{
    Expression<Func<Product, bool>> filter = Build<Product>(field, op, value);
    var names = products.AsQueryable().Where(filter).Select(p => p.Name);
    Console.WriteLine($"{filter,-38} => {string.Join(", ", names)}");
}

static Expression<Func<T, bool>> Build<T>(string field, string op, object value)
{
    ParameterExpression p = Expression.Parameter(typeof(T), "p");
    MemberExpression left = Expression.Property(p, field);
    ConstantExpression right = Expression.Constant(value, left.Type);

    Expression body = op switch
    {
        "==" => Expression.Equal(left, right),
        ">" => Expression.GreaterThan(left, right),
        "<" => Expression.LessThan(left, right),
        ">=" => Expression.GreaterThanOrEqual(left, right),
        "<=" => Expression.LessThanOrEqual(left, right),
        _ => throw new ArgumentException($"Unknown operator {op}"),
    };
    return Expression.Lambda<Func<T, bool>>(body, p);
}

record Product(string Name, string Category, decimal Price);
```

### Combining Filters With And

Users usually pick **multiple** filters. You combine them with `Expression.AndAlso`, which is the tree version of `&&`.

Each filter has its own input `p`, so the combined tree must use **one shared input**. A small visitor swaps the inputs.

```csharp runnable title="Combine two filters into one"
using System;
using System.Linq;
using System.Linq.Expressions;

Expression<Func<Product, bool>> inKitchen = p => p.Category == "Kitchen";
Expression<Func<Product, bool>> cheap = x => x.Price < 2000m;

var both = And(inKitchen, cheap);
Console.WriteLine(both);

var products = new[]
{
    new Product("Kettle", "Kitchen", 1299m),
    new Product("Mixer", "Kitchen", 3499m),
    new Product("Lamp", "Home", 899m),
};
Console.WriteLine(string.Join(", ", products.AsQueryable().Where(both).Select(p => p.Name)));

static Expression<Func<T, bool>> And<T>(Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
    ParameterExpression shared = first.Parameters[0];
    Expression secondBody = new SwapParameter(second.Parameters[0], shared).Visit(second.Body);
    return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(first.Body, secondBody), shared);
}

class SwapParameter(ParameterExpression from, ParameterExpression to) : ExpressionVisitor
{
    protected override Expression VisitParameter(ParameterExpression node) => node == from ? to : node;
}

record Product(string Name, string Category, decimal Price);
```

## Expression Trees in LINQ

Now you see why LINQ has **two** sets of methods with the same names.

- **`Enumerable.Where`** works on `IEnumerable<T>`. It takes a **`Func<T, bool>`** delegate and runs it on each item in memory.
- **`Queryable.Where`** works on `IQueryable<T>`. It takes an **`Expression<Func<T, bool>>`** tree and does **not** run it right away. It adds the tree to the query.

You write the same lambda for both. The compiler picks a delegate or a tree based on which method you call.

```csharp runnable title="IQueryable collects a tree instead of running code"
using System;
using System.Linq;

int[] marks = { 35, 72, 91, 58, 44 };

var inMemory = marks.Where(m => m >= 50);            // IEnumerable<int>
var asQuery = marks.AsQueryable().Where(m => m >= 50) // IQueryable<int>
                                 .OrderBy(m => m);

Console.WriteLine($"Enumerable: {string.Join(", ", inMemory)}");
Console.WriteLine($"Queryable:  {string.Join(", ", asQuery)}");

Console.WriteLine("The query's tree:");
Console.WriteLine($"  {asQuery.Expression}");
Console.WriteLine($"  Root node: {asQuery.Expression.NodeType}");
```

`asQuery.Expression` holds the whole query as a tree: the source, then the `Where`, then the `OrderBy`. A **query provider** decides what to do with that tree. Here, the provider is the in-memory one, so it compiles and runs it. A database provider does something different.

If you save a filter in a `Func<T, bool>` variable and pass it to `Where` on an `IQueryable`, C# picks **`Enumerable.Where`**. The whole table is loaded into memory first, then filtered. Keep database filters as `Expression<Func<T, bool>>` so they stay translatable.

## Expression Trees in ORM Frameworks

An **ORM** (Object-Relational Mapper) like **Entity Framework Core** lets you ask a database using LINQ. It cannot run your C# lambda inside SQL Server. So it reads the **tree** instead and translates each node into SQL.

With EF Core, this C# query:

```text
var bigOrders = db.Orders
    .Where(o => o.Total > 1000 && o.City == "Pune")
    .OrderBy(o => o.Total)
    .Select(o => o.Id)
    .ToList();
```

becomes SQL that looks like this, which runs on the database server:

```text
SELECT [o].[Id]
FROM [Orders] AS [o]
WHERE [o].[Total] > 1000.0 AND [o].[City] = N'Pune'
ORDER BY [o].[Total]
```

This needs a real database, so it is shown as plain code. But the core idea is just an `ExpressionVisitor`. Here is a tiny translator that turns a filter tree into a SQL `WHERE` clause:

```csharp runnable title="A mini ORM: translate a filter into SQL"
using System;
using System.Linq.Expressions;
using System.Text;

Console.WriteLine(ToSql<Order>(o => o.Total > 1000 && o.City == "Pune"));
Console.WriteLine(ToSql<Order>(o => o.City != "Delhi" || o.Total <= 500));

static string ToSql<T>(Expression<Func<T, bool>> filter)
{
    var writer = new SqlWriter();
    writer.Visit(filter.Body);
    return $"SELECT * FROM {typeof(T).Name}s WHERE {writer.Sql}";
}

class SqlWriter : ExpressionVisitor
{
    private readonly StringBuilder _sql = new();
    public string Sql => _sql.ToString();

    protected override Expression VisitBinary(BinaryExpression node)
    {
        _sql.Append('(');
        Visit(node.Left);
        _sql.Append(node.NodeType switch
        {
            ExpressionType.AndAlso => " AND ",
            ExpressionType.OrElse => " OR ",
            ExpressionType.Equal => " = ",
            ExpressionType.NotEqual => " <> ",
            ExpressionType.GreaterThan => " > ",
            ExpressionType.LessThanOrEqual => " <= ",
            _ => throw new NotSupportedException(node.NodeType.ToString()),
        });
        Visit(node.Right);
        _sql.Append(')');
        return node;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        _sql.Append($"[{node.Member.Name}]");
        return node;
    }

    protected override Expression VisitConstant(ConstantExpression node)
    {
        _sql.Append(node.Value is string s ? $"'{s.Replace("'", "''")}'" : node.Value);
        return node;
    }
}

class Order
{
    public decimal Total { get; set; }
    public string City { get; set; } = "";
}
```

Real ORMs handle many more node types, use SQL parameters instead of pasting values, and support joins. But the way works the same: visit the tree and write SQL for each node.

This also explains a common EF Core error. If your lambda calls **your own C# method**, the ORM finds a `MethodCallExpression` it does not know how to turn into SQL:

```text
db.Orders.Where(o => IsVip(o.Customer)).ToList();
// InvalidOperationException: The LINQ expression '...IsVip(o.Customer)'
// could not be translated.
```

The ORM can only translate things it knows. Your private C# method does not exist inside the database.

## Where Expression Trees Are Used

- **Entity Framework Core** and other ORMs turn LINQ into SQL.
- **Dynamic filters** in search pages and grids build `Where` clauses while the program runs.
- **Mapping libraries** like AutoMapper compile fast copy code.
- **Validation libraries** like FluentValidation read `x => x.Email` to get the property name.
- **Mocking libraries** like Moq read `m => m.Send(It.IsAny<string>())` to set up fakes.
- **Serializers and DI containers** compile fast readers and constructors.

## Common mistakes

| Mistake | Symptom | Fix |
|---|---|---|
| Calling a tree directly | `CS0149` | `Compile()` first |
| Statement lambda as a tree | `CS0834` | Use a single expression |
| Two different inputs | "variable referenced from scope" | Swap inputs with a visitor |
| Mixed types in a hand-built node | `InvalidOperationException` | Match types, or use `Expression.Convert` |
| `Func` passed to an `IQueryable` | Whole table loaded into memory | Keep it as `Expression<Func<...>>` |
| `Compile()` in a loop | Slow code | Compile one time and keep it |
| Own method inside an EF Core query | "could not be translated" | Move the logic outside the query |

## What to Remember

- An expression tree stores code as data that other code can read.
- `Func<...>` is compiled code. `Expression<Func<...>>` is a tree of the same lambda.
- Every piece of a tree is a node with a `NodeType` and a `Type`.
- Only single-expression lambdas can become trees.
- Build trees by hand with `Expression.Parameter`, `Constant`, `Add`, `Property`, `Call` and `Lambda`.
- `Compile()` turns a tree into a delegate. It is slow, so compile one time and keep the delegate.
- `ExpressionVisitor` reads or changes trees. Trees never change. Visitors give back new ones.
- Combine filters with `Expression.AndAlso` and one shared input.
- `IQueryable` collects a tree. A provider decides how to run it.
- ORMs like EF Core translate trees into SQL. They can only handle what they understand.

Next: Dependency Injection
