.NET Framework を対象とする Windows デスクトップ アプリケーションは、特定のプログラミング言語で記述され、中間言語 (IL) にコンパイルされます。 実行時に、Just-In-Time (JIT) コンパイラは、メソッドが初めて実行される直前に、ローカル コンピューターのネイティブ コードに IL をコンパイルする役割を担います。 これに対し、.NET ネイティブ ツール チェーンは、コンパイル時にソース コードをネイティブ コードに変換します。 この記事では、.NET Native と .NET Framework アプリで使用できる他のコンパイル テクノロジを比較し、.NET Native でコンパイルされたコードで発生する例外が JIT コンパイル コードで発生しない理由を理解するのに役立つネイティブ コードを生成する方法の実用的な概要を示します。
ネイティブ バイナリの生成
.NET Framework を対象とし、.NET ネイティブ ツール チェーンを使用してコンパイルされないアプリケーションは、次を含むアプリケーション アセンブリで構成されます。
アセンブリ、その依存関係、含まれる型、およびそのメンバーを記述するメタデータ。 メタデータはリフレクションおよび遅延バインド アクセスに使用され、場合によってはコンパイラやビルド ツールでも使用されます。
実装コード。 これは中間言語 (IL) オペコードで構成されます。 実行時に、Just-In-Time (JIT) コンパイラによってターゲット プラットフォームのネイティブ コードに変換されます。
メイン アプリケーション アセンブリに加えて、アプリには次のものが必要です。
アプリに必要な追加のクラス ライブラリまたはサード パーティ製アセンブリ。 これらのアセンブリには同様に、アセンブリ、その型、およびそのメンバーを記述するメタデータと、すべての型メンバーを実装する IL が含まれます。
.NET Framework クラス ライブラリ。 これは、.NET Framework インストールを使用してローカル システムにインストールされるアセンブリのコレクションです。 .NET Framework クラス ライブラリに含まれるアセンブリには、メタデータと実装コードの完全なセットが含まれています。
共通言語ランタイム。 これは、アセンブリの読み込み、メモリ管理とガベージ コレクション、例外処理、Just-In-Time コンパイル、リモート処理、相互運用などのサービスを実行するダイナミック リンク ライブラリのコレクションです。 クラス ライブラリと同様に、ランタイムは .NET Framework インストールの一部としてローカル システムにインストールされます。
アプリを正常に実行するには、共通言語ランタイム全体、およびアプリケーション固有のアセンブリ、サードパーティアセンブリ、およびシステム アセンブリのすべての型のメタデータと IL が存在する必要があることに注意してください。
ジャストインタイムコンパイル
.NET ネイティブ ツール チェーンの入力は、C# または Visual Basic コンパイラによってビルドされた UWP アプリです。 言い換えると、言語コンパイラが UWP アプリのコンパイルを完了すると、.NET ネイティブ ツール チェーンの実行が開始されます。
ヒント
.NET Native への入力はマネージド アセンブリに書き込まれた IL とメタデータであるため、ビルド前またはビルド後のイベントを使用するか、MSBuild プロジェクト ファイルを変更することで、カスタム コードの生成やその他のカスタム操作を実行できます。
ただし、IL を変更して .NET ツール チェーンがアプリの IL を分析できないようにするツールのカテゴリはサポートされていません。 難読化器は、このタイプの最も注目すべきツールです。
アプリを IL からネイティブ コードに変換する過程で、.NET ネイティブ ツール チェーンは次のような操作を実行します。
特定のコード パスでは、リフレクションとメタデータに依存するコードを静的なネイティブ コードに置き換えます。 たとえば、値型が ValueType.Equals メソッドをオーバーライドしない場合、等価性の既定のテストではリフレクションを使用して、値型のフィールドを表す FieldInfo オブジェクトを取得し、2 つのインスタンスのフィールド値を比較します。 ネイティブ コードにコンパイルする場合、.NET ネイティブ ツール チェーンはリフレクション コードとメタデータをフィールド値の静的比較に置き換えます。
可能であれば、すべてのメタデータを削除しようとします。
最終的なアプリ アセンブリには、アプリによって実際に呼び出される実装コードのみが含まれます。 これは、サード パーティ製ライブラリおよび .NET Framework クラス ライブラリのコードに特に影響します。 その結果、アプリケーションはサード パーティ製ライブラリまたは完全な .NET Framework クラス ライブラリに依存しなくなります。代わりに、サードパーティおよび .NET Framework クラス ライブラリのコードがアプリに対してローカルになりました。
完全な CLR は、主にガベージ コレクターを含むリファクタリングされたランタイムに置き換えられます。 リファクタリングされたランタイムは、mrt100_app.dll という名前のライブラリにあり、アプリに対してローカルであり、サイズはわずか数百キロバイトです。 静的リンクを使用すると、共通言語ランタイムによって実行される多くのサービスが不要になるため、これが可能です。
注
.NET Native では、標準の共通言語ランタイムと同じガベージ コレクターが使用されます。 .NET ネイティブ ガベージ コレクターでは、バックグラウンド ガベージ コレクションが既定で有効になっています。 ガベージ コレクションの詳細については、「 ガベージ コレクションの基礎」を参照してください。
Von Bedeutung
.NET Native は、アプリケーション全体をネイティブ アプリケーションにコンパイルします。 マネージド コードから独立して呼び出すことができるように、クラス ライブラリを含む 1 つのアセンブリをネイティブ コードにコンパイルすることはできません。
.NET ネイティブ ツール チェーンによって生成された結果のアプリは、プロジェクト ディレクトリの Debug ディレクトリまたは Release ディレクトリ内の ilc.out という名前のディレクトリに書き込まれます。 これは、次のファイルで構成されます。
appName
.exe 、appName .dllで特別な エクスポートに制御 転送するスタブ実行可能ファイルです。 <appName>.dll。すべてのアプリケーション コードを含む Windows ダイナミック リンク ライブラリ、.NET Framework クラス ライブラリのコード、および依存関係のあるサードパーティ製ライブラリ。 また、Windows との相互運用やアプリ内のオブジェクトのシリアル化に必要なコードなどのサポート コードも含まれています。
mrt100_app.dll:ガベージ コレクションなどのランタイム サービスを提供するリファクタリングされたランタイム。
すべての依存関係は、アプリの APPX マニフェストによってキャプチャされます。 appx パッケージに直接バンドルされているアプリケーション exe、dll、mrt100_app.dllに加えて、これにはさらに 2 つのファイルが含まれます。
msvcr140_app.dll、mrt100_app.dllによって使用される C ランタイム (CRT) ライブラリです。 パッケージ内のフレームワーク参照に含まれています。
mrt100.dll. このライブラリには、mrt100_app.dllのパフォーマンスを向上できる関数が含まれていますが、存在しない場合でも、mrt100_app.dll は機能しません。 ローカル コンピューター上の system32 ディレクトリ (存在する場合) から読み込まれます。
.NET ネイティブ ツール チェーンは、アプリがそのコードを実際に呼び出す場合にのみ、実装コードをアプリにリンクするため、次のシナリオで必要なメタデータまたは実装コードがアプリに含まれていない可能性があります。
反射。
動的呼び出しまたは遅延バインド呼び出し。
シリアル化と逆シリアル化。
COM 相互運用機能。
実行時に必要なメタデータまたは実装コードがない場合、.NET ネイティブ ランタイムは例外をスローします。 これらの例外を回避し、.NET ネイティブ ツール チェーンに必要なメタデータと実装コードが含まれていることを確認できます。 ランタイム ディレクティブ ファイルを使用して、メタデータまたは実装コードを実行時に使用でき、ランタイム ポリシーを割り当てる必要があるプログラム要素を指定する XML ファイルです。 .NET ネイティブ ツール チェーンによってコンパイルされる UWP プロジェクトに追加される既定のランタイム ディレクティブ ファイルを次に示します。
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<Assembly Name="*Application*" Dynamic="Required All" />
</Application>
</Directives>
これにより、リフレクションと動的呼び出しのために、アプリ パッケージ内のすべてのアセンブリ内のすべての型とそのすべてのメンバーが有効になります。 ただし、.NET Framework クラス ライブラリ アセンブリの型のリフレクションまたは動的なアクティブ化は有効になりません。 多くの場合、これは適切です。