AST C#で理解しようとしています。この例のCompile()
メソッドが正確に何をしているのでしょうか。
_// Some code skipped
Expression<Func<string, int, int, string>> data = Expression.Lambda<Func<string, int, int, string>>(
Expression.Call(s, typeof(string).GetMethod(“Substring”, new Type[] { typeof(int), typeof(int) }), a, b),
s, a, b
);
Func<string, int, int, string> fun = data.Compile();
_
誤解を防ぐために、私は_Expression.Lambda
_および_Expression.Call
_構文を理解しています。興味深いのは、Compile()
メソッドです。それはどういうわけか本当のMSILを生成しますか? MSILを見ることができますか?
興味深いのは、
Compile()
メソッドです。それはどういうわけか本当のMSILを生成しますか?
はい。 Compileメソッドは、ラムダボディブロックに対してビジターを実行し、各部分式に対して動的にILを生成します。
ILを自分で吐き出す方法を学ぶことに興味がある場合は、 軽量のCodegenの使用方法のこの「Hello World」の例 を参照してください。 (部分的に信頼されたappdomainでLightweight Codegenを使用しなければならないという不幸な立場にいる場合、制限されたスキップの可視性のある世界では事態が少し奇妙になる可能性があることに注意してください。 Shawn Farkasの記事 を参照してください興味がある場合は、件名を入力してください。)
MSILを見ることができますか?
はい。ただし、特別な「ビジュアライザ」が必要です。 Compile()
のデバッグに使用したビジュアライザーは、その一部を実装しているときにここからダウンロードできます。
http://blogs.msdn.com/b/haibo_luo/archive/2005/10/25/484861.aspx
式は、データ構造を式ツリーの形式で表します。 Compile()
を使用して、この式ツリーをデリゲート( "メソッド"の形式で実行可能コードにコンパイルできます。 "呼び出し)。
コンパイル後、通常はデリゲートを呼び出すことができます。この例では、デリゲートはFunc<string,int,int,string>
です。このアプローチは、対応するデリゲートを作成して実行することを最終目標として、実行時にのみ利用できるデータに基づいて式ツリーを動的に作成するときに必要になる場合があります。
デリゲートの「コード」は表示されません。それが基にしている表現ツリー自体がそれに最も近い。
これに対する答えは今や部分的に古くなっており、起こっていることが時々しかありません。
ILへの式のコンパイルには、特にAOTで常に使用できるわけではないReflection.Emitが必要です。したがって、それらの場合、ILにコンパイルする代わりに、式は命令を表すオブジェクトのリストに「コンパイル」されます。これらの各命令には、適切なアクションを実行させるRun
メソッドがあり、ILがスタックで動作するのと同じように、値のスタックで動作します。これらのオブジェクトでRun
を呼び出すメソッドは、デリゲートとして返すことができます。
通常、このようなデリゲートの実行は、ILを出力するよりも遅くなりますが、ILへのコンパイルが利用できない場合の唯一のオプションであり、コンパイル手順が高速であることが多いため、インタープリターを使用した場合よりもインタープリターを使用した場合の方が、コンパイルと実行の合計時間が短くなります。単発式のIL。
そのため、.NET Coreでは、ILへのコンパイルが利用可能であっても、解釈を要求するブール値を取得するCompile
のオーバーロードが存在します。
これらはすべて、興味深い言語の組み合わせになります。式自体は言語であり、アセンブリはC#で記述されており、ILにコンパイルでき、解釈された命令オブジェクトは第4言語を構成します。