Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Visiting and rewriting trees

โญโญโญ advancedโณ 15 min read๐Ÿ“ Lesson 190 of 265

ExpressionVisitor as the universal transformer: what EF does to your predicates.

Visiting and rewriting trees

ExpressionVisitor walks a tree and rebuilds it, calling VisitXxx per node kind. Override only what you change; Visit handles recursion and reconstruction:

class TenantFilter : ExpressionVisitor
{
    protected override Expression VisitBinary(BinaryExpression node)
    {
        var left = Visit(node.Left);
        var right = Visit(node.Right);
        return node.Update(left, node.Conversion, right);
    }
    protected override Expression VisitConstant(ConstantExpression node)
        => node.Value is int v && v == 42 ? Expression.Constant(43) : node;
}

This is precisely what EF Core does: your Where(o => o.Tenant == "a") is visited, the member access becomes a column, the constant becomes a parameter, and the tree is re-emitted as SQL. Visitors are also how you implement optimization passes (constant folding, predicate pushdown) and safety passes (rejecting unsupported constructs with a clear message).

Two patterns worth knowing: bottom-up transforms (fold children first โ€” constant folding) and top-down guards (validate before descending โ€” provider translation). Returning the ORIGINAL node (via node.Update(...)) when nothing changed lets the visitor skip rebuilding untouched subtrees โ€” cheap immutability in action.

โšก Now practice

Ready to Code
Expression drillsVisitors, constant folding, a mini provider, and the per-call-compile trap.
3 challenges ยท ยท ~45 min