2011-10-14 13 views
43

Expression<>の中にデリゲートをラップすることとは違いますか?Expressionクラスの目的は何ですか?

私は012QがLinQと多く使われているのを見ていますが、これまでのところ、これの違いを説明しているデリゲートを使用した記事は見つかりませんでした。

など。

Expression<Func<int, bool>> Is42 = (value) => value == 42; 

答えて

48

ラムダをデリゲートとして格納すると、何らかのアクションを行うデリゲートの特定のインスタンスが格納されます。それは変更することはできません、あなたはそれを呼び出すだけです。デリゲートを取得したら、それが何をしているのか、それ以外のものを調べるオプションは限られています。

ラムダを式として格納すると、デリゲートを表す式ツリーが格納されます。パラメータを変更したり、ボディを変更したり、根本的に異なる何かをさせるなど、他の操作を行うように操作することができます。デリゲートにコンパイルすることもできますので、必要に応じて呼び出すことができます。表現を簡単に調べて、そのパラメータが何であるか、それが何であり、どのようにしているかを見ることができます。これは、クエリプロバイダが式を理解し、別の言語に翻訳するために使用できます(対応する式ツリーのSQLクエリを作成するなど)。

表現を使用してデリゲートを動的に作成することも、コードを出力するよりもずっと簡単です。あなたのコードは、コンパイラがコードを低レベルにするのではなくコードを見る方法と非常に似ていると考えることができます。

表現では、単純な匿名デリゲート以上のことができます。実際にフリーではありませんが、コンパイルされた式を通常のメソッドや匿名のデリゲートと比較して実行すると、パフォーマンスが低下します。ただし、式を使用することによるその他の利点が重要な場合があるため、それは問題ではない可能性があります。

+0

これは私にとって完璧に明確になりました:-) – Steffen

13

Func<>

Func<int, bool> Is42 = (value) => value == 42; 

対はちょうどデリゲート型です。式は、任意に、実行時にデリゲートにコンパイルされるoperationsという完全なツリーのランタイム表現です。この木はLinq-to-SQLのようなExpressionパーサによって解析され、SQL文を生成したり他の巧妙なことを行います。式の型にラムダを割り当てると、コンパイラはこの式ツリーと通常のILコードを生成します。 More on expression trees

4

表現ツリーノードを表すクラスが派生する基底クラスを提供します。

System.Linq.Expressions.BinaryExpression 
System.Linq.Expressions.BlockExpression 
System.Linq.Expressions.ConditionalExpression 
System.Linq.Expressions.ConstantExpression 
System.Linq.Expressions.DebugInfoExpression 
System.Linq.Expressions.DefaultExpression 
System.Linq.Expressions.DynamicExpression 
System.Linq.Expressions.GotoExpression 
System.Linq.Expressions.IndexExpression 
System.Linq.Expressions.InvocationExpression 
System.Linq.Expressions.LabelExpression 
System.Linq.Expressions.LambdaExpression 
System.Linq.Expressions.ListInitExpression 
System.Linq.Expressions.LoopExpression 
System.Linq.Expressions.MemberExpression 
System.Linq.Expressions.MemberInitExpression 
System.Linq.Expressions.MethodCallExpression 
System.Linq.Expressions.NewArrayExpression 
System.Linq.Expressions.NewExpression 
System.Linq.Expressions.ParameterExpression 
System.Linq.Expressions.RuntimeVariablesExpression 
System.Linq.Expressions.SwitchExpression 
System.Linq.Expressions.TryExpression 
System.Linq.Expressions.TypeBinaryExpression 
System.Linq.Expressions.UnaryExpression 

http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx

式ツリーを分析し、例えばSQLクエリに変換することができますLINQの式を表します。

4

Expression Treesコード内の式内のコードを検査することができます。

たとえば、この式を渡した場合、o => o.Nameは、Nameプロパティが式の中でアクセスされていることをコードが知ることができます。

9

あなたがそれらの2式をコンパイルした場合、他の回答を示しており、コンパイラ生成されたコードを見て、この私は何が表示されますするには、次の

Func<int, bool> Is42 = (value) => value == 42;

Func<int, bool> Is42 = new Func<int, bool>((@value) => value == 42); 


Expression<Func<int, bool>> Is42 = (value) => value == 42;

ParameterExpression[] parameterExpressionArray; 
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "value"); 
Expression<Func<int, bool>> Is42 = Expression.Lambda<Func<int, bool>>(Expression.Equal(parameterExpression, Expression.Constant(42, typeof(int))), new ParameterExpression[] { parameterExpression }); 
+0

? – Phil

+4

彼はどのような違いがあり、生成されたコードは違いを自明に尋ねていました。 – Ucodia

2

他の人が書いたもの(完全に正しい)には、Expressionクラスを通して、実行時に新しいメソッドを作成できることを追加します。いくつかの制限があります。 C#でできることはすべて、Expressionツリー(少なくとも.NET 3.5では.Net 4.0では可能な限り多数の「タイプ」が追加されています)で行うことができます。これを使用すると、動的クエリを作成してLINQ-to-SQLに渡したり、ユーザーの入力に基づいてフィルタリングを行うことができます(たとえば、CodeDomでこれを行うことができます)LINQ-to-SQLと互換性のない動的なメソッドでしたが、直接ILコードを発行するのはかなり難しいです:-))

関連する問題