式ツリー は、ツリーに似たデータ構造のコードを表します。各ノードは式です。たとえば、メソッド呼び出しや、 x < y
などのバイナリ操作です。
LINQ を使用した場合、 Func
型が API セットの一部であるリッチ ライブラリを使用した経験があります。 (LINQ に慣れていない場合は、LINQ チュートリアル と、この前に ラムダ式 に関する記事を読む必要があります)。式ツリーは、関数である引数とのより豊富な相互作用を提供します。
関数引数は、LINQ クエリを作成するときに、通常はラムダ式を使用して記述します。 一般的な LINQ クエリでは、これらの関数引数はコンパイラによって作成されるデリゲートに変換されます。
式ツリーを使用するコードはすでに記述されています。 Entity Framework の LINQ API は、LINQ クエリ式パターンの引数として式ツリーを受け入れます。 これにより、 Entity Framework では、C# で記述したクエリを、データベース エンジンで実行される SQL に変換できます。 もう 1 つの例として、.NET 用の一般的なモック フレームワークである Moq があります。
より豊富な操作を行う場合は、 式ツリーを使用する必要があります。 式ツリーは、コードを、確認、変更、または実行する構造体として表します。 これらのツールを使用すると、実行時にコードを操作できます。 実行中のアルゴリズムを調べたり、新しい機能を挿入したりするコードを記述します。 より高度なシナリオでは、実行中のアルゴリズムを変更し、別の環境で実行するために C# 式を別の形式に変換します。
式ツリーで表されるコードをコンパイルして実行します。 式ツリーをビルドして実行すると、実行可能コードの動的な変更、さまざまなデータベースでの LINQ クエリの実行、動的クエリの作成が可能になります。 LINQ の式ツリーの詳細については、「式ツリー を使用して動的クエリを作成する方法」を参照してください。
式ツリーは、動的言語ランタイム (DLR) でも使用され、動的言語と .NET 間の相互運用性を提供し、コンパイラ ライターが Microsoft 中間言語 (CIL) ではなく式ツリーを出力できるようにします。 DLR の詳細については、「 動的言語ランタイムの概要」を参照してください。
C# または Visual Basic コンパイラで匿名ラムダ式に基づいて式ツリーを作成することも、 System.Linq.Expressions 名前空間を使用して式ツリーを手動で作成することもできます。
ラムダ式が Expression<TDelegate>型の変数に割り当てられると、コンパイラはラムダ式を表す式ツリーを構築するコードを出力します。
次のコード例では、C# コンパイラでラムダ式 num => num < 5
を表す式ツリーを作成する方法を示します。
Expression<Func<int, bool>> lambda = num => num < 5;
コードで式ツリーを作成します。 ツリーを構築するには、各ノードを作成し、ノードをツリー構造にアタッチします。 式 ツリーの構築に関する記事では、式を作成する方法について説明します。
式ツリーは変更できません。 式ツリーを変更する場合は、既存の式ツリーをコピーし、その中のノードを置き換えて、新しい式ツリーを構築する必要があります。 式ツリー ビジターを使用して、既存の式ツリーをトラバースします。 詳細については、 式ツリーの変換に関する記事を参照してください。
式ツリーを作成したら、 式ツリーで表されるコードを実行します。
制限事項
C# コンパイラは、式ラムダ (または単一行ラムダ) からのみ式ツリーを生成します。 ステートメントラムダ (または複数行ラムダ) を解析することはできません。 C# のラムダ式の詳細については、「 ラムダ式」を参照してください。
式ツリーにうまく変換されない新しい C# 言語要素がいくつかあります。 式ツリーには、 await
式や async
ラムダ式を含めることはできません。 C# 6 以降で追加された機能の多くは、式ツリーで記述されているとおりには表示されません。 代わりに、新しい機能は、可能な場合は同等の以前の構文で式ツリーで公開されます。 その他のコンストラクトは使用できません。 これは、新しい言語機能が導入されたときに、式ツリーを解釈するコードが同じように動作することを意味します。 ただし、これらの制限がある場合でも、式ツリーを使用すると、データ構造として表されるコードの解釈と変更に依存する動的アルゴリズムを作成できます。 これにより、Entity Framework などの豊富なライブラリで、その機能を実現できます。
式ツリーでは、新しい式ノードの種類はサポートされません。 式ツリーを解釈するすべてのライブラリが新しいノードタイプを導入するのは破壊的変更です。 次の一覧には、使用できないほとんどの C# 言語要素が含まれています。
- 出力から削除された条件付きメソッド
-
base
アクセス - メソッド グループの式 (メソッド グループのアドレス (
&
) や匿名メソッド式を含む) - ローカル関数への参照
- 代入 (
=
) やステートメント形式の式を含むステートメント - 定義宣言のみを持つ部分メソッド
- 安全でないポインター操作
-
dynamic
オペレーションズ -
左側に
null
またはdefault
リテラルがある合体演算子、null 合体代入 、および null 伝搬演算子 (?.
) - 多次元配列初期化子、 インデックス付きプロパティ、ディクショナリ初期化子
- コレクション式
-
throw
式 -
static virtual
またはabstract
インターフェイス メンバーへのアクセス - 属性を持つラムダ式
- 補間された文字列
- UTF-8 文字列変換または UTF-8 文字列リテラル
- 変数引数、名前付き引数、または省略可能な引数を使用したメソッド呼び出し
-
System.Index または System.Range を使用する式、 末尾からのインデックス演算子 (
^
) または、範囲演算子 (..
) -
async
ラムダ式またはawait
式、await foreach
およびawait using
を含む -
タプル リテラル、タプル変換、タプル
==
または!=
、またはwith
式 -
破棄 (
_
)、分解代入、パターン マッチングis
演算子、またはパターンマッチングswitch
式 - 引数の
ref
が省略された COM 呼び出し -
ref
、in
またはout
のパラメーター、ref
の戻り値、out
の引数、またはref struct
型の任意の値
.NET