Skip to content

MS_ExpressionTree

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

式木(Expression Tree)

概要

  • 式木(Expression tree)とは、式(数式)を木構造で表したものの事。
  • 以前は、1 文だけのラムダ式のみ式木(Expression tree)にできた。
  • .NET 4 から、強化され DLR で使っている構文木の全機能を備える。

補足(何が嬉しいのか): 通常、ラムダ式は
**コンパイルされてデリゲート(実行可能なコード)**になる。
式木は、それを **「コードの構造そのもの(データ)」**として保持する。

// ① デリゲート:実行できるが、中身は覗けない
Func<int, bool> f = x => x > 5;

// ② 式木:実行できないが、構造を解析できる
Expression<Func<int, bool>> e = x => x > 5;

e は次のような木になっている。

         BinaryExpression (GreaterThan)
           ├── ParameterExpression (x)
           └── ConstantExpression (5)

この「構造を読める」という性質から、次の 2 つの使い道が生まれる。

用途 内容
別の言語へ翻訳する 木を辿って SQL を組み立てる(LINQ プロバイダ)
コードを生成して高速化する 木を組み立てて Compile() し、デリゲートにする

なお、Expression<T>Compile() でデリゲートに変換できるが、
逆(デリゲート → 式木)はできない。

詳細

使用例

実際に、文字列の計算式の計算結果を取得するライブラリでは、
RPN(Reverse Polish Notation、逆ポーランド記法)や
式木(Expression Tree)を使って計算するライブラリなどがある。

補足(eval 相当が .NET に無い理由): JavaScript の eval
Python の eval に相当するものが .NET の標準にはない
(静的型付け言語であり、実行時にコンパイラを持たないため)。

このため「文字列の数式を計算する」には、

  1. 自前で構文解析して RPN に変換し、スタックで評価する
  2. 式木を組み立てて Compile() する(何度も評価するなら速い)、
  3. Roslyn Scripting APIMicrosoft.CodeAnalysis.CSharp.Scripting)を使う、

という選択肢がある。3 は C# のコードをそのまま実行できるが、
コンパイラを丸ごと抱えることになるため重い(.NETコンパイラ)。

LINQとの関連

LINQプロバイダでは、ラムダ式を式木として扱う

補足(IEnumerableIQueryable の分岐点): LINQ には
2 つの入口があり、式木を使うかどうかがその違いである。

IEnumerable<T>(LINQ to Objects) IQueryable<T>(LINQ to SQL/EF)
引数の型 Func<T, bool>デリゲート Expression<Func<T, bool>>(式木)
評価場所 メモリ上で 1 件ずつ評価 木を SQL に翻訳して DB 側で評価
結果 全件取ってから絞る DB で絞ってから取る
// ① IQueryable:WHERE 句に翻訳され、DB 側で絞られる
db.Users.Where(u => u.Age > 20).ToList();

// ② AsEnumerable() を挟むと…全件取得してからメモリで絞る
db.Users.AsEnumerable().Where(u => u.Age > 20).ToList();

② は結果は同じだが、テーブル全件がアプリに流れてくる
EF Core での性能事故の典型がこれで、
「なぜ式木なのか」を理解していないと踏みやすい。

また、式木として翻訳できないメソッド(自作メソッドなど)を
Where の中で呼ぶと、EF Core では実行時に例外になる
(EF6 までは暗黙にクライアント評価へフォールバックしていたが、
事故のもとであったため EF Core 3.0 で既定で例外に変わった)。

参考

Microsoft Learn

Sho's

(プログラミング C# - 翔ソフトウェア (Sho's))

[C#][ラムダ式][式木]

Expression として扱えるラムダ式と扱えないラムダ式
http://blog.shos.info/archives/2012/11/cexpression_expression.html

[C#][.NET][式木]

メタプログラミング入門

実装


Tags: 移行, プログラミング, .NET開発

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally