質問: これは単なる好奇心であり、現実の世界の助けにはならない。 私は表現木で、通常のC#コンパイラのように、飛行機でMSILを生成できることを知っています。コンパイラは最適化を決めることができるので、 `Expression.Compile()`中にILがどのように生成されたのかを知りたいです。基本的に2つの質問: 1. コンパイル時に、コンパイラは*デバッグモードとリリースモード*で異なるILを作成することができるため、 *デバッグモードとリリースモード*でビルドされたときに式をコンパイルすることによって生成されるILに違いはありますか? 2. 実行時にILをネイティブコードに変換するJITも、デバッグモードとリリースモードの両方で大きく異なるはずです。コンパイルされた式の場合もそうですか?あるいは、ILは全く表現されていない表現木から来ていますか? 私の理解には欠陥があるかもしれません。 **注:**私はデバッガが切り離されている場合を考えています。私はビジュアルスタジオで "デバッグ"と "リリース"に付属するデフォルトの設定の設定について質問しています。
回答: > コンパイル時に、コンパイラはデバッグモードとリリースモードで異なるILを作成することができるため、デバッグモードとリリースモードでビルドされたときに式をコンパイルすることによって生成されるILに違いはありますか? > > これは実際には非常に単純な答えです:いいえ。 2つの同一のLINQ / DLRエクスプレッションツリーが与えられている場合、リリースモードで実行中のアプリケーションによってコンパイルされ、デバッグモードで実行されるアプリケーションでコンパイルされると、生成されたILに違いはありません。とにかくそれがどうやって実装されるのか分かりません。 `System.Core`内のコードで、プロジェクトでデバッグビルドまたはリリースビルドが実行されていることを確認するための信頼できる方法はわかりません。 しかし、この回答は実際には誤解を招く可能性があります。式コンパイラによって生成されるILは、デバッグとリリースビルドの間で異なることはありませんが、C#コンパイラによって式ツリーが生成される場合、デバッグモードとリリースモードの間で式ツリー自体の構造が異なる可能性があります。私はLINQ / DLRの内部についてはよく知っていますが、C#コンパイラではあまり知られていないので、これらのケースでは違いが*ある*としか言えません。 > 実行時にILをネイティブコードに変換するJITも、デバッグモードとリリースモードの両方で大きく異なるはずです。コンパイルされた式の場合もそうですか?あるいは、ILは全く表現されていない表現木から来ていますか? > > JITコンパイラが吐き出すマシンコードは、最適化されていないILと最適化されていないILでは*大きく*異なるとは限りません。唯一の違いがいくつか余分な一時的な値である場合は特に、結果は同じである可能性があります。私は、JITが所与の方法を最適化するのに費やす時間/努力の上限が通常あるので、より大きくてより複雑な方法で2つがより大きく分かれると思う。しかし、コンパイルされたLINQ / DLR式ツリーの品質が、たとえばデバッグモードまたはリリースモードでコンパイルされたC#コードとどのように比較されるかに関心があるように思えます。 私は、LINQ / DLR `LambdaCompiler`はリリースモードではC#コンパイラよりも少ない最適化`LambdaCompiler`実行していないと言います。デバッグモードは近いかもしれませんが、私はC#コンパイラの方がやや積極的です。 `LambdaCompiler`一般的に一時的なローカルの使用を減らそうとはしませんし、条件付き、比較、型変換などの操作では通常、予想以上に中間地方を使用します。私は実際に実行する3つの最適化について考えること*が*できます: 1. 可能であればネストされたラムダはインライン展開されます(可能な場合は「ほとんどの時間」になる傾向があります)。これは、実際には、多くの助けになることができます。これは、 `LambdaExpression`を`Invoke`ときにのみ機能します。式の中でコンパイルされたデリゲートを呼び出す場合は適用されません。 2. 不必要な/重複した型の変換は、少なくとも場合によっては省略されます。 3. コンパイル時に`TypeBinaryExpression`の値(つまり`[value] is [Type]` )がわかっている場合、その値は定数としてインライン化されます。 #3とは別に、式コンパイラは「式ベースの」最適化を行いません。つまり、最適化の機会を探している表現木は分析されません。リスト内の他の最適化は、ツリー内の他の式についてほとんどまたは全くコンテキストなしで行われます。 一般的に、コンパイルされたLINQ / DLR式から生成されたILは、C#コンパイラによって生成されたILよりも大幅に最適化されていないと想定する必要があります。ただし、結果として生じるILコード**はJIT最適化**に**適格である**ため、実際に同等のコードで測定しようとしない限り、実世界のパフォーマンスへの影響を評価することは困難です。 式ツリーを使用してコードを作成するときに心に留めておくべきことの一つは、実際には、 *あなたが*コンパイラ1であることがあります。 LINQ / DLRツリーは、さまざまなDLR言語実装のような他のコンパイラインフラストラクチャによって生成されるように設計されています。したがって、式レベルで最適化を処理するのは*あなた次第です* 。あなたがうっかりしないコンパイラであり、不要なコードや冗長なコードを生成すると、生成されるILは大きくなり、JITコンパイラによって積極的に最適化される可能性は低くなります。ですから、あなたが作った表現には気をつけましょうが、あまりにも心配しないでください。あなたが高度に最適化されたILを必要とするならば、おそらく自分でそれを出すべきです。しかし、ほとんどの場合、LINQ / DLRツリーは正常に動作します。 1 LINQ / DLR式が正確な型の照合を必要とすることに懐疑的である理由を疑問に思ったことがある場合は、複数の言語のコンパイラターゲットとして機能することが意図されており、したがって、LINQ / DLRツリーを手動で構築する際には、暗黙的な変換のためのコードを自動的に挿入するなど、通常はバックグラウンドでコンパイラが行う作業を行う必要があります。