また更新が遅くなってしまいました。
C# 3.0 で新しく追加された Expression Tree は 言語の中の Semantic Tree を .NET の アセンブリに書き出しデータとして扱えるようにするための機能です。 Express Tree ですから semantic tree の Node は Expression つまり式だけになります。
Expression Tree を C# 3.0 で書き出す方法の一つは
Expression<Func<int, bool>> filter = n => n < 5;
ildasm.exe をIL使ってみて頂くと分かると思いますが、以下のようなコードがC#コンパイラによって生成されています。
...
...
IL_0023: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0028: call class [System.Query]System.Expressions.ConstantExpression [System.Query]System.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
IL_002d: call class [System.Query]System.Expressions.BinaryExpression [System.Query]System.Expressions.Expression::LT(class [System.Query]System.Expressions.Expression,class [System.Query]System.Expressions.Expression)
IL_0032: ldc.i4.1
IL_0033: newarr [System.Query]System.Expressions.ParameterExpression
...
...
何か起こっているか? 結局はコンパイラが以下のコードを書き出していると思っていただければと思います。
Expression<Func<int, bool>> filter = Expression.Lambda<Func<int, bool>>(
Expression.LT( // Less Thanオペレータ
Expression.Parameter(typeof(int), "n"), // ラムダ式のパラメタ名
Expression.Constant(5, typeof(int)) // コンスタント式
),
new ParameterExpression[] { Expression.Parameter(typeof(int), "n") }
);
もちろん、Lambda 式と使った時上のコードは同一の Expression Tree が作られます。
ではなぜこの様な Data Structure が必要かというと、C# のコードがILに直接にコンパイルされた場合、言語の中のセマンティックスが失われてしまいます。 例えば上の例の中にあるLess Than オペレータは簡単な比較とジャンプのIL のオプコードを使って表現されます。 Expression Tree をつかうことによって、直接 Less Than の Node をコードから使えるようになります。 もし Expression Tree がなかった場合、DLINQ などの機能を実現するには、IL を IL Stream を使って取り出し Semantic Analysis を IL に対してしなくてはならなくなってしまいます。
明日のトピックは Expression Tree Basic Edition 2 の予定です。