Looking for c# Answers? Try Ask4KnowledgeBase
Looking for c# Keywords? Try Ask4Keywords

C# Language表現木


前書き

式木は、等長のデータ構造で配列された式です。ツリーの各ノードは式の表現であり、式はコードです。ラムダ式のインメモリ表現は、クエリの実際の要素(すなわちコード)を保持するが、その結果は保持しない式ツリーになります。式ツリーは、ラムダ式の構造を透明かつ明示的にする。

構文

  • 式<TDelegate> name = lambdaExpression;

パラメーター

パラメータ詳細
TDelegate 式に使用されるデリゲート型
ラムダ式ラムダ式(例: num => num < 5

備考

表現木の紹介

私たちが来たところ

式ツリーは、すべて実行時に "ソースコード"を消費します。受注decimal CalculateTotalTaxDue(SalesOrder order)基づいて売上税を計算する方法を考えてみましょう。 .NETプログラムでそのメソッドを使用するのは簡単です - 単にdecimal taxDue = CalculateTotalTaxDue(order); 。リモートクエリ(SQL、XML、リモートサーバなど)のすべての結果に適用する場合はどうすればよいですか?これらのリモートクエリソースはメソッドを呼び出すことはできません!伝統的には、これらすべてのケースでフローを反転させる必要があります。クエリ全体をメモリに保存し、結果をループして結果ごとに税金を計算します。

フローインバージョンのメモリとレイテンシの問題を回避する方法

式ツリーは、各ノードが式を保持するツリー形式のデータ構造です。それらは、データベースクエリのようなプログラム環境の外部で使用できる式でコンパイルされた命令(データをフィルタリングするために使用されるメソッドのような)を翻訳するために使用されます。

ここでの問題は、リモートクエリが私たちのメソッドにアクセスできないことです。代わりに、メソッドの命令をリモートクエリに送信した場合、この問題を回避できます。 CalculateTotalTaxDue例では、この情報を送信します。

  1. 総税を格納する変数を作成する
  2. 注文のすべての行をループする
  3. 各行について、商品が課税対象かどうかを確認する
  4. そうである場合は、行合計に適用税率を掛け、その合計を合計に加算します
  5. それ以外は何もしない

これらの指示で、リモートクエリはデータを作成するときに作業を実行できます。

これを実装するには2つの課題があります。コンパイルされた.NETメソッドを命令のリストに変換する方法と、リモートシステムで使用できる方法で命令をどのようにフォーマットするのですか?

表現木がなければ、MSILの最初の問題を解決することしかできませんでした。 (MSILは.NETコンパイラによって作成されたアセンブラのようなコードです)。MSILの解析は可能です 、簡単ではありません。たとえそれを正しく解析したとしても、元のプログラマーの意図が特定のルーチンであったかどうかを判断するのは難しいでしょう。

式ツリーはその日を節約する

式ツリーは、これらの正確な問題に対処します。それらはプログラム命令をツリーデータ構造で表し、各ノードは1つの命令を表し、その命令を実行するために必要なすべての情報を参照します。たとえば、 MethodCallExpressionは、1)呼び出すMethodInfo 、2)そのメソッドに渡すExpressionのリスト、3)メソッドのメソッド、メソッドを呼び出すExpressionを参照します。あなたは "ツリーを歩いて"あなたのリモートクエリに指示を適用することができます。

式ツリーの作成

式ツリーを作成する最も簡単な方法は、ラムダ式を使用する方法です。これらの式は、通常のC#メソッドとほぼ同じです。これがコンパイラの魔法であることを理解することが重要です。最初にラムダ式を作成すると、コンパイラはそのラムダ式に何を割り当てるかをチェックします。 Delegate型( ActionまたはFuncを含む)の場合、コンパイラはラムダ式をデリゲートに変換します。 LambdaExpression (または厳密に型指定されたLambdaExpressionExpression<Action<T>>またはExpression<Func<T>> )の場合、コンパイラはLambdaExpression変換します。背後では、コンパイラは式ツリーAPIを使ってラムダ式をLambdaExpressionに変換します。

ラムダ式は、あらゆるタイプの式ツリーを作成することはできません。そのような場合は、Expressions APIを手動で使用して、必要なツリーを作成することができます。 式API理解の例では、 APIを使用してCalculateTotalSalesTax式を作成します。

注:名前はここで少し混乱します。 ラムダ式 (2つの単語、小文字)は、 =>標識付きのコードブロックを参照します。これはC#での匿名メソッドを表し、 DelegateまたはExpression変換されます。 LambdaExpression (1つの単語、PascalCase)は、実行可能なメソッドを表すExpression API内のノード型を参照します。

式ツリーとLINQ

式ツリーの最も一般的な用途の1つは、LINQとデータベースクエリです。 LINQは式ツリーをクエリプロバイダとペアにして、対象のリモートクエリに命令を適用します。たとえば、LINQ to Entity Frameworkクエリプロバイダは、式ツリーをSQLに変換し、データベースに対して直接実行します。

すべての要素をまとめてみると、LINQの真のパワーを見ることができます。

  1. ラムダ式を使用してクエリを書く: products.Where(x => x.Cost > 5)
  2. コンパイラは、その式を式ツリーに変換し、 "パラメータのCostプロパティが5より大きいかどうかを確認する"という指示を出します。
  3. 問合せプロバイダは式ツリーを解析し、有効なSQL問合せを生成しますSELECT * FROM products WHERE Cost > 5
  4. ORMはすべての結果をPOCOに投影し、オブジェクトのリストを取得します

ノート

  • 式ツリーは不変です。式ツリーを変更するには、新しいツリーを作成する必要があります。既存のツリーを新しいツリーにコピーし( ExpressionVisitor Treeを使用して、 ExpressionVisitorを使用できます)、必要な変更を行います。

表現木 関連する例