web-dev-qa-db-ja.com

ダミーの表現ツリー?

私はこのシナリオではダミーです。

これらをGoogleで読んでみましたが、わかりません。誰かが私にそれらが何であるか、そしてなぜそれらが役立つのかについて簡単な説明をくれますか?

編集:私は.NetのLINQ機能について話している。

66
Dave

私が今まで読んだ式ツリーについての最も良い説明は、チャーリー・カルバートによる この記事 です。

まとめると、

式ツリーは、必要な方法ではなく、何をしたいかを表しますそれをするために。

次の非常に単純なラムダ式について考えてみます。
Func<int, int, int> function = (a, b) => a + b;

このステートメントは、3つのセクションで構成されています。

  • 宣言:_Func<int, int, int> function_
  • 等号演算子:_=_
  • ラムダ式:_(a, b) => a + b;_

変数functionは、2つの数値を加算する方法が知っている生の実行可能コードを指します

これは、デリゲートと式の最も重要な違いです。渡した2つの整数で何が行われるかを知らずに、function(a _Func<int, int, int>_)を呼び出します。それは2つを取り、1つを返します、それはあなたのコードが知ることができるほとんどです。

前のセクションでは、生の実行可能コードを指す変数を宣言する方法を説明しました。 式ツリーは実行可能コードではありません。これらはデータ構造の形式です。

これで、デリゲートとは異なり、コードは式ツリーが何をするのかを知ることができます

LINQは、コードを式ツリーと呼ばれるデータ構造に変換するための簡単な構文を提供します。最初のステップは、usingステートメントを追加して_Linq.Expressions_名前空間を導入することです。

_using System.Linq.Expressions;_

これで、式ツリーを作成できます。
Expression<Func<int, int, int>> expression = (a, b) => a + b;

前の例で示したものと同じラムダ式は、タイプ_Expression<T>_として宣言された式ツリーに変換されます。識別子expressionは実行可能コードではありません。これは、式ツリーと呼ばれるデータ構造です。

つまり、デリゲートを呼び出すのと同じように式ツリーを呼び出すだけでなく、分析することもできます。では、変数expressionを分析することで、コードは何を理解できるでしょうか。

_// `expression.NodeType` returns NodeType.Lambda.
// `expression.Type` returns Func<int, int, int>.
// `expression.ReturnType` returns Int32.

var body = expression.Body;
// `body.NodeType` returns ExpressionType.Add.
// `body.Type` returns System.Int32.

var parameters = expression.Parameters;
// `parameters.Count` returns 2.

var firstParam = parameters[0];
// `firstParam.Name` returns "a".
// `firstParam.Type` returns System.Int32.

var secondParam = parameters[1].
// `secondParam.Name` returns "b".
// `secondParam.Type` returns System.Int32.
_

ここでは、式から取得できる情報がたくさんあることがわかります。

しかし、なぜそれが必要なのでしょうか?

式ツリーは実行可能コードを表すデータ構造であることを学びました。しかし、これまでのところ、なぜそのような変換をしたいのかという中心的な質問には答えていません。これは、この投稿の冒頭で私たちが尋ねた質問です。今がその答えです。

LINQ to SQLクエリは、C#プログラム内では実行されません。代わりに、SQLに変換され、ネットワーク経由で送信され、データベースサーバーで実行されます。つまり、次のコードがプログラム内で実際に実行されることはありません。
_var query = from c in db.Customers where c.City == "Nantes" select new { c.City, c.CompanyName };_

最初に次のSQLステートメントに変換され、サーバーで実行されます。
_SELECT [t0].[City], [t0].[CompanyName] FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] = @p0_

クエリ式で見つかったコードは、別のプロセスに文字列として送信できるSQLクエリに変換する必要があります。この場合、そのプロセスはSQLサーバーデータベースです。生のILまたは実行可能コードをSQLに変換するよりも、式ツリーなどのデータ構造をSQLに変換する方がはるかに簡単です。問題の難しさを多少誇張するために、一連の0と1をSQLに変換することを想像してみてください。

クエリ式をSQLに変換するときが来たら、前のセクションで単純なラムダ式ツリーを分解したのと同じように、クエリを表す式ツリーを分解して分析します。確かに、LINQ to SQL式ツリーを解析するアルゴリズムは、使用したアルゴリズムよりもはるかに洗練されていますが、原理は同じです。式ツリーの部分を分析すると、LINQはそれらをまとめて、要求されたデータを返すSQLステートメントを記述する最適な方法を決定します。

式ツリーは、クエリ式などのコードを文字列に変換して、他のプロセスに渡してそこで実行できるようにするために作成されました。とても簡単です。ここには大きな謎はなく、振る必要のある魔法の杖はありません。コードを取得してデータに変換し、データを分析して、別のプロセスに渡すことができる文字列に変換される構成部分を見つけるだけです。

クエリはこのような抽象データ構造にカプセル化されたコンパイラーに送られるため、コンパイラーは自由にそれを自由に解釈できます。クエリを特定の順序で、または特定の方法で実行する必要はありません。代わりに、式ツリーを分析し、やりたいことを見つけてから、その方法を決定できます。少なくとも理論的には、現在のネットワークトラフィック、データベースの負荷、データベースで使用可能な現在の結果セットなど、さまざまな要因を自由に検討できます。実際には、LINQ to SQLはこれらすべての要因を考慮しません、しかしそれはそれが望んでいることをほとんどすることは理論的に自由です。さらに、この式ツリーを手動で記述したカスタムコードに渡して、それを分析し、LINQ to SQLで生成されるものとは非常に異なるものに変換することができます。

ここでも、式ツリーを使用して、表現したい(表現しますか?)何をしたいかを確認できます。そして、表現がどのように使用されるかをどのように決定するトランスレータを使用するか

59
Şafak Gür

式ツリーは、式のメモリ内表現です。算術式またはブール式。たとえば、算術式を考えます

a + b*2

*は+よりも演算子の優先順位が高いため、式ツリーは次のように構築されます。

    [+]
  /    \
 a     [*]
      /   \
     b     2

このツリーがあれば、aとbの値を評価できます。さらに、たとえば、式を派生させるために、それを他の式ツリーに変換できます。

式ツリーを実装するときは、基本クラスExpressionを作成することをお勧めします。それから派生した、クラスBinaryExpressionは、+や*などのすべてのバイナリ式に使用されます。次に、VariableReferenceExpressionを参照変数(aやbなど)に導入し、別のクラスConstantExpression(例の2の場合)。

式ツリーは、多くの場合、入力を(ユーザーから直接、またはファイルから)解析した結果として構築されます。式ツリーを評価するには、 ビジターパターン を使用することをお勧めします。

14
EFrank

短い答え:同じ種類のLINQクエリを記述して、任意のデータソースを指すことができるのは素晴らしいことです。これがないと、 "Language Integrated"クエリを作成できませんでした。

長い答え:おそらくご存じのとおり、ソースコードをコンパイルすると、ある言語から別の言語にソースコードが変換されます。通常、高級言語(C#)から(IL)の下位レベルまで。

これを行うには、基本的に2つの方法があります。

  1. 検索と置換を使用してコードを翻訳できます
  2. コードを解析して、解析ツリーを取得します。

後者は、「コンパイラ」として知られているすべてのプログラムが行うことです。

解析ツリーを作成したら、他の言語に簡単に変換できます。これが、式ツリーで実行できることです。コードはデータとして保存されるので、やりたいことは何でもできますが、おそらく他の言語に翻訳したいだけでしょう。

これで、LINQ to SQLでは、式ツリーがSQLコマンドに変換され、ネットワーク経由でデータベースサーバーに送信されます。私が知る限り、コードを翻訳するとき、彼らは何も特別なことはしませんが、couldです。たとえば、クエリプロバイダーは、ネットワークの状態に応じて異なるSQLコードを作成できます。

14
Rodrick Chapman

IIUC、式ツリーは抽象構文ツリーに似ていますが、式は通常、単一の値を生成しますが、ASTはプログラム全体を表すことができます(クラス、パッケージ、関数、ステートメントなど) 。)

とにかく、式(2 + 3)* 5の場合、ツリーは次のようになります。

    *
   / \ 
  +   5
 / \
2   3

各ノードを再帰的に(ボトムアップで)評価して、ルートノードの値、つまり式の値を取得します。

もちろん、単項(否定)または三項(if-then-else)演算子と、式言語で許可されている場合は関数(n-ary、つまり任意の数のops)も使用できます。

タイプの評価とタイプ制御の実行は、同様のツリーで行われます。

5
Macke

DLR
式ツリーは、動的言語ランタイム(DLR)をサポートするためのC#への追加です。 DLRは、変数を宣言する "var"メソッドを提供する役割もあります。 (var objA = new Tree();

DLRの詳細

基本的に、Microsoftは、LISP、Smalltalk、Javascriptなどの動的言語用にCLRをオープンしたいと考えていました。そのためには、式をその場で解析および評価できる必要がありました。 DLRが登場するまで、それは不可能でした。

最初の文に戻ると、式ツリーはC#への追加であり、DLRを使用する機能を開きます。以前は、C#ははるかに静的な言語でした。すべての変数の型は特定の型として宣言する必要があり、すべてのコードはコンパイル時に記述する必要がありました。

データで使用する
式ツリーは、動的コードへの水門を開きます。

たとえば、不動産サイトを作成しているとします。設計段階では、適用できるすべてのフィルターを知っています。このコードを実装するには、2つの選択肢があります。各データポイントを一連のIf-Thenチェックと比較するループを作成できます。または、動的言語(SQL)でクエリを作成し、それを検索を実行できるプログラム(データベース)に渡すこともできます。

式ツリーを使用すると、プログラムのコードをその場で変更して、検索を実行できます。具体的には、LINQを使用してこれを行うことができます。

(詳細: MSDN:方法:式ツリーを使用して動的クエリを作成する )。

Beyond data
式ツリーの主な用途は、データの管理です。ただし、動的に生成されたコードにも使用できます。したがって、動的に定義される関数(Javascript)が必要な場合は、式ツリーを作成してコンパイルし、結果を評価できます。

私はもう少し深く行きますが、このサイトははるかに良い仕事をします:

コンパイラとしての式ツリー

リストされている例には、変数タイプの汎用演算子の作成、手動ローリングラムダ式、高性能のシャロークローニング、オブジェクト間の読み取り/書き込みプロパティの動的なコピーが含まれます。

まとめ
式ツリーは、実行時にコンパイルおよび評価されるコードの表現です。データ操作や動的プログラミングに役立つ動的型を使用できます。

3
Richard