C# 式ツリー(Expression Tree)入門
式ツリー(Expression Tree)は、ラムダ式をコードとしてではなく「データ構造」として扱う仕組みです。Entity Framework などの ORM が、ラムダ式を SQL に変換できるのはこの機能のおかげです。
式ツリーとは
通常、ラムダ式はコンパイル時に実行可能なコード(デリゲート)に変換されます。一方、式ツリーとして扱うと、ラムダ式の構造そのものがオブジェクトとして保持されます。
using System.Linq.Expressions;
// デリゲート:実行可能なコード
Func<int, int> funcSquare = x => x * x;
// 式ツリー:式の構造を表すデータ
Expression<Func<int, int>> exprSquare = x => x * x;見た目は同じラムダ式ですが、型が Func か Expression<Func> かで扱いが変わります。
式ツリーの構造を見る
式ツリーは、式の各部分をノードとして持つ木構造になっています。
Expression<Func<int, int>> expr = x => x * x;
Console.WriteLine(expr.Body); // (x * x)
Console.WriteLine(expr.Parameters[0]); // x
Console.WriteLine(expr.NodeType); // LambdaBody プロパティで式の本体にアクセスでき、さらにその内部構造を辿ることもできます。
式ツリーをコンパイルして実行
式ツリーは Compile() メソッドでデリゲートに変換し、実行できます。
Expression<Func<int, int, int>> expr = (a, b) => a + b;
// 式ツリーをデリゲートにコンパイル
Func<int, int, int> func = expr.Compile();
Console.WriteLine(func(3, 5)); // 8Entity Framework での活用
Entity Framework では、式ツリーを解析して SQL クエリに変換します。
// このラムダ式は式ツリーとして解釈される
var query = dbContext.Users
.Where(u => u.Age >= 20 && u.IsActive);Where に渡されたラムダ式は、実行されるのではなく解析されます。そして u.Age >= 20 && u.IsActive という条件が SQL の WHERE 句に変換されるのです。
LINQ to Objects(Func を使用)
メモリ上のコレクションに対して、ラムダ式がそのまま実行される
LINQ to Entities(Expression を使用)
ラムダ式が解析され、SQL などの別言語に変換される
制限事項
式ツリーに変換できるのは「式形式ラムダ」のみです。文形式ラムダは式ツリーにできません。
// OK:式形式
Expression<Func<int, int>> valid = x => x * 2;
// エラー:文形式は式ツリーにできない
// Expression<Func<int, int>> invalid = x => { return x * 2; };式ツリーは高度な機能ですが、ORM やコード生成など、C# のエコシステムを支える重要な基盤となっています。