Windows 8.x アプリを .NET Native に移行する

.NET Native では、Microsoft Store または開発者のコンピューターでのアプリの静的コンパイルが提供されます。 これは、デバイス上で Just-In-Time (JIT) コンパイラまたはネイティブ イメージ ジェネレーター (Ngen.exe) によって Windows 8.x アプリ (以前は Microsoft Store アプリとも呼ばれました) に対して実行される動的なコンパイルとは異なります。 違いはありますが、.NET Native では、Windows 8.x アプリ用 .NET との互換性を保持しようとしています。 ほとんどの場合、Windows 8.x アプリ用 .NET で動作する機能は、.NET Native でも動作します。 ただし、動作に違いがある場合もあります。 このドキュメントでは、以下の分野における標準 Windows 8.x アプリ用 .NET と .NET Native との、これらの違いについて説明します。

全般的なランタイムの違い

  • アプリが共通言語ランタイム (CLR) で実行されているときに JIT コンパイラによってスローされる TypeLoadException などの例外は、通常、.NET Native によって処理されるときにはコンパイル時エラーになります。

  • アプリの UI スレッドから GC.WaitForPendingFinalizers メソッドを呼び出さないでください。 これにより .NET Native でデッドロックが発生する可能性があります。

  • 静的クラス コンストラクターの呼び出し順序に依存しないでください。 .NET Native では、呼び出し順序が標準ランタイムでの順序と異なります (標準ランタイムを使用する場合であっても、静的クラス コンストラクターの実行順序に依存しないでください)。

  • スレッドでの呼び出しを行わない無限ループ (たとえば、 while(true);) によって、アプリが停止する可能性があります。 同様に、長時間または無限の待機によってもアプリが停止する可能性があります。

  • .NET Native では、特定の汎用初期化サイクルで例外がスローされません。 たとえば、次のコードは標準 CLR では TypeLoadException 例外をスローします。 .NET Native ではそうではありません。

    using System;
    
    struct N<T> {}
    struct X { N<X> x; }
    
    public class Example
    {
       public static void Main()
       {
          N<int> n = new N<int>();
          X x = new X();
       }
    }
    
  • 場合によっては、.NET Native では、.NET Framework クラス ライブラリのさまざまな実装が用意されます。 メソッドから返されるオブジェクトは、常に、返される型のメンバーを実装します。 ただし、その補助的な実装が異なるため、その他の .NET Framework プラットフォームの場合と同じ型セットへのオブジェクトのキャストを行うことができない場合があります。 たとえば、 IEnumerable<T>TypeInfo.DeclaredMembers などのメソッドにより返される TypeInfo.DeclaredProperties インターフェイス オブジェクトを T[]にキャストできない場合があります。

  • WinInet キャッシュは、Windows 8.x アプリ用 .NET では既定で有効ではありませんが、.NET Native では有効です。 これによりパフォーマンスが向上しますが、作業セットへの影響があります。 開発者のアクションは必要ありません。

動的プログラミングの違い

.NET Native は、.NET Framework のコードに静的にリンクし、コードをアプリローカルにすることでパフォーマンスを最大にします。 ただし、バイナリ サイズは小さいままである必要があるため、.NET Framework 全体を取り入れることはできません。 .NET Native コンパイラは、未使用のコードへの参照を削除する依存関係レジューサを使用して、この制限を解決します。 ただし、.NET Native では、型情報をコンパイル時に静的に推論できず、代わりに実行時に動的に取得される場合、一部の型情報やコードが維持または生成されないことがあります。

.NET Native では、リフレクションと動的プログラミングが可能です。 ただし、生成されるコードのサイズが大きくなりすぎるため、すべての型をリフレクション用にマークできるわけではありません (特に、.NET Framework のパブリック API でのリフレクションがサポートされているため)。 .NET Native コンパイラは、どの型でリフレクションをサポートする必要があるかを適切に判断し、それらの型についてのみメタデータを維持し、コードを生成します。

たとえば、データ バインディングは、プロパティ名を関数にマップするためにアプリを必要とします。 Windows 8.x アプリ用 .NET では、共通言語ランタイムが自動的にリフレクションを使用して、マネージド型と一般公開されているネイティブ型にこの機能を提供します。 .NET Native では、データのバインド先の型のメタデータが、コンパイラによって自動的にインクルードされます。

.NET Native コンパイラでは、ヒントやディレクティブなしで機能する List<T>Dictionary<TKey,TValue> などの一般的に使用されるジェネリック型も処理できます。 dynamic キーワードも、一定の制限の下でサポートされます。

注意

アプリを .NET Native に移植するときには、すべての動的コード パスを十分にテストする必要があります。

ほとんどの開発者にとっては .NET Native の既定の構成で十分ですが、開発者によっては、ランタイム ディレクティブ (.rd.xml) ファイルを使用した構成の微調整が必要となる場合もあります。 さらに、場合によっては、.NET Native コンパイラが、どのメタデータがリフレクション用に使用できる必要があるかを判断できず、特に次のような場合に、ヒントを利用することがあります。

  • Type.MakeGenericTypeMethodInfo.MakeGenericMethod などの一部の構造体は、静的に決定できません。

  • コンパイラでインスタンス化を決定できないため、リフレクション対象のジェネリック型をランタイム ディレクティブで指定する必要があります。 これは、すべてのコードを含める必要があるだけではなく、ジェネリック型へのリフレクションによって無限サイクルが生じる可能性があるためです (たとえば、ジェネリック型でジェネリック メソッドが呼び出された場合)。

注意

ランタイム ディレクティブは、ランタイム ディレクティブ (.rd.xml) ファイルで定義されます。 このファイルの使用方法に関する全般的な情報は、「Getting Started with .NET Native」(.NET ネイティブの概要) をご覧ください。 ランタイム ディレクティブについては、「 Runtime Directives (rd.xml) Configuration File Reference」をご覧ください。

.NET Native には、既定セット以外のどの型でリフレクションをサポートするかを開発者が決定するときに役立つプロファイル ツールも含まれています。

Windows 8.x アプリ用 .NET と .NET Native の動作には、他にも多くのリフレクション関連の違いがあります。

.NET Native では:

  • .NET Framework クラス ライブラリでの型とメンバーに対するプライベート リフレクションはサポートされません。 ただし、独自のプライベート型とメンバー、およびサードパーティ ライブラリの型とメンバーに対するリフレクションは行うことができます。

  • ParameterInfo.HasDefaultValue プロパティは、戻り値を表す false オブジェクトに対し、正しく ParameterInfo を返します。 Windows 8.x アプリ用 .NET では、true が返されます。 これに対する中間言語 (IL) による直接的なサポートはなく、解釈は言語に任されます。

  • RuntimeFieldHandle 構造体と RuntimeMethodHandle 構造体のパブリック メンバーはサポートされません。 これらの型は、LINQ、式ツリー、および静的な配列の初期化でのみサポートされます。

  • RuntimeReflectionExtensions.GetRuntimePropertiesRuntimeReflectionExtensions.GetRuntimeEvents の基底クラスには隠ぺいされたメンバーが含まれるため、明示的なオーバーライドなしでオーバーライドできます。 これは、その他の RuntimeReflectionExtensions.GetRuntime* メソッドの場合も同様です。

  • 特定の組み合わせ (たとえば、byref オブジェクトの配列) を作成しようとしたときに、Type.MakeArrayTypeType.MakeByRefType が失敗することはありません。

  • リフレクションを使用して、ポインター パラメーターを持つメンバーを呼び出すことはできません。

  • リフレクションを使用して、ポインター フィールドを取得または設定することはできません。

  • 引数カウントが間違っていて、いずれかの引数の型が正しくない場合、.NET Native では TargetParameterCountException ではなく ArgumentException がスローされます。

  • 通常、例外のバイナリ シリアル化はサポートされません。 そのため、シリアル化不可能なオブジェクトを Exception.Data ディクショナリに追加できます。

サポートされていないシナリオと API

次のセクションに、全般的な開発、相互運用、および HTTPClient や Windows Communication Foundation (WCF) などの技術でサポートされないシナリオと API を示します。

全般的な開発の違い

値型

  • 値型の ValueType.Equals メソッドと ValueType.GetHashCode メソッドをオーバーライドする場合は、基底クラスの実装を呼び出さないでください。 Windows 8.x アプリ用 .NET では、これらのメソッドはリフレクションに依存します。 コンパイル時、.NET Native では、ランタイム リフレクションに依存しない実装が生成されます。 つまり、これら 2 つのメソッドをオーバーライドしなければ、.NET Native によるコンパイル時に実装が生成されるため、これらは期待どおりに動作します。 ただし、基底クラスの実装を呼び出さずにこれらのメソッドをオーバーライドすると、例外が発生します。

  • 1 メガバイトより大きい値型はサポートされません。

  • .NET Native では、値型でパラメーターなしのコンストラクターを使用することはできません (C# と Visual Basic では、値型のパラメーターなしのコンストラクターが禁止されています。ただし、これらは IL で作成できます)。

配列

  • ゼロ以外の下限を持つ配列はサポートされません。 通常、これらの配列は Array.CreateInstance(Type, Int32[], Int32[]) オーバーロードを呼び出すことで作成されます。

  • 多次元配列の動的作成はサポートされません。 そのような配列は通常、 Array.CreateInstance パラメーターを含む lengths メソッドのオーバーロードを呼び出すか、 Type.MakeArrayType(Int32) メソッドを呼び出すことで作成されます。

  • 4 つ以上の次元を持つ多次元配列 (つまり、 Array.Rank プロパティ値が 4 以上のもの) はサポートされません。 代わりに ジャグ配列 (配列の配列) を使用してください。 たとえば、 array[x,y,z] は無効ですが、 array[x][y][z] は有効です。

  • 多次元配列の共変性はサポートされず、実行時に InvalidCastException 例外を発生させます。

ジェネリック

  • ジェネリック型の無限展開はコンパイル エラーになります。 たとえば、このコードはコンパイルに失敗します。

    class A<T> {}
    
    class B<T> : A<B<A<T>>>
    {}
    

ポインター

  • ポインターの配列はサポートされていません。

  • リフレクションを使用して、ポインター フィールドを取得または設定することはできません。

シリアル化

KnownTypeAttribute(String) 属性はサポートされていません。 代わりに KnownTypeAttribute(Type) 属性を使用してください。

リソース

EventSource クラスでのローカライズされたリソースの使用はサポートされません。 EventSourceAttribute.LocalizationResources プロパティはローカライズされたリソースを定義しません。

デリゲート

Delegate.BeginInvokeDelegate.EndInvoke はサポートされません。

その他の API

  • GuidAttribute 属性が型に適用されない場合、TypeInfo.GUID プロパティは PlatformNotSupportedException 例外をスローします。 GUID は主に COM サポートで使用されます。

  • .NET Native では、DateTime.Parse メソッドで、短い日付を含む文字列が正しく解析されます。 ただし、日付と時刻の解析の特定の変更との互換性は維持されません。

  • BigInteger.ToString("E") は、.NET Native では正しく丸められます。 CLR の一部のバージョンでは、結果の文字列が丸められるのではなく、切り捨てられます。

HttpClient の違い

.NET Native では、HttpClientHandler クラスは、標準の Windows 8.x アプリ用 .NET で使用される WebRequest クラスおよび WebResponse クラスではなく、WinINet を内部的に使用します (HttpBaseProtocolFilter クラスを通じて)。 WinINet では、 HttpClientHandler クラスでサポートされる構成オプションがすべてサポートされるわけではありません。 その結果、次のような影響が出ています。

  • HttpClientHandler の機能プロパティのいくつかは、.NET Native では false を返しますが、標準の Windows 8.x アプリ用 .NET では true を返します。

  • 一部の構成プロパティ get アクセサーは、.NET Native では常に固定値を返しますが、この値は Windows 8.x アプリ用 .NET での既定の構成可能値とは異なります。

次のサブセクションで、その他の動作の違いについて説明します。

Proxy

HttpBaseProtocolFilter クラスで、要求ごとのプロキシの構成とオーバーライドはサポートされません。 つまり、.NET Native では、すべての要求でシステム構成のプロキシ サーバーが使用されるか、プロキシ サーバーは使用されません (HttpClientHandler.UseProxy プロパティの値によって決まります)。 Windows 8.x アプリ用 .NET では、プロキシ サーバーは HttpClientHandler.Proxy プロパティによって定義されます。 .NET Native では、HttpClientHandler.Proxynull 以外の値に設定すると、PlatformNotSupportedException 例外がスローされます。 HttpClientHandler.SupportsProxy プロパティは、.NET Native では false を返しますが、標準の Windows 8.x アプリ用 .NET Framework では true を返します。

自動リダイレクト

HttpBaseProtocolFilter クラスでは、自動リダイレクトの最大数の構成が許可されません。 標準の Windows 8.x アプリ用 .NET では、HttpClientHandler.MaxAutomaticRedirections プロパティの値は既定で 50 であり、変更できます。 .NET Native では、このプロパティの値は 10 であり、変更しようとすると PlatformNotSupportedException 例外がスローされます。 HttpClientHandler.SupportsRedirectConfiguration プロパティは、.NET Native では false を返しますが、Windows 8.x アプリ用 .NET では true を返します。

自動展開

Windows 8.x アプリ用 .NET では、HttpClientHandler.AutomaticDecompression プロパティを DeflateGZipDeflateGZip の両方、または None に設定できます。 .NET Native では、DeflateGZip の両方に設定するか None のみがサポートされます。 AutomaticDecompression プロパティを Deflate のみまたは GZip のみに設定しようとすると、 DeflateGZipの両方に自動的に設定されます。

Cookie

クッキーの処理は、 HttpClient と WinINet により同時に行われます。 CookieContainer のクッキーは、WinINet クッキー キャッシュのクッキーと組み合わされます。 CookieContainer のクッキーを削除すると HttpClient からクッキーが送信されませんが、クッキーが既に WinINet に示されており、ユーザーによって削除されない場合、WinINet がクッキーを送信します。 HttpClientHttpClientHandler、または CookieContainer API を使用して、プログラムにより WinINet からクッキーを削除することはできません。 HttpClientHandler.UseCookies プロパティを false に設定しても、 HttpClient からクッキーが送信されなくなるのみで、WinINet の要求にはまだそのクッキーが含まれている可能性があります。

資格情報

Windows 8.x アプリ用 .NET では、HttpClientHandler.UseDefaultCredentials プロパティと HttpClientHandler.Credentials プロパティは独立して動作します。 また、 Credentials プロパティは ICredentials インターフェイスを実装するオブジェクトをすべて受け入れます。 .NET Native では、UseDefaultCredentials プロパティを true に設定すると、Credentials プロパティが null になります。 さらに、 Credentials プロパティは、 nullDefaultCredentials、または NetworkCredential型のオブジェクトにしか設定できません。 その他の ICredentials オブジェクト (最も一般的なものは CredentialCache) を Credentials プロパティに割り当てると、 PlatformNotSupportedExceptionがスローされます。

その他のサポートされていない機能または構成できない機能

.NET Native では:

相互運用の違い

非推奨の API

マネージド コードで相互運用性のために使用される頻度が低い API のいくつかが、非推奨にされました。 .NET Native でこれらの API を使用すると、NotImplementedException または PlatformNotSupportedException 例外がスローされるか、コンパイラ エラーになる場合があります。 Windows 8.x アプリ用 .NET では、これらの API は廃止としてマークされていますが、それらを呼び出した場合、コンパイラ エラーではなくコンパイラ警告が生成されます。

非推奨の VARIANT マーシャリング用 API には、以下が含まれます。

UnmanagedType.Struct はサポートされていますが、一部のシナリオ (IDispatchbyref バリアントと共に使用された場合など) では例外がスローされます。

非推奨の IDispatch サポート用 API には、以下が含まれます。

非推奨のクラシック COM イベント用 API には、以下が含まれます。

非推奨の System.Runtime.InteropServices.ICustomQueryInterface インターフェイスの API (.NET Native では非サポート) には、以下が含まれます。

その他のサポートされない相互運用機能には、以下が含まれます。

ほとんど使用されないマーシャリング API:

プラットフォーム呼び出しと COM 相互運用の互換性

ほとんどのプラットフォーム呼び出しと COM 相互運用シナリオは、.NET Native でもサポートされます。 特に、Windows ランタイム (WinRT) API とのすべての相互運用性と Windows ランタイムで必要なすべてのマーシャリングがサポートされます。 これには、次のものに対するマーシャリング サポートが含まれます。

ただし、.NET Native では、以下はサポートされません。

リフレクションを使用したプラットフォーム呼び出しメソッドの呼び出しはサポートされません。 この制限を回避するには、別のメソッドでメソッド呼び出しをラップし、リフレクションを使用してラッパーを代わりに呼び出します。

Windows 8.x 用 .NET API とのその他の違い

このセクションには、.NET Native でサポートされないその他の API を示します。 サポートされない API で最も多いのは、Windows Communication Foundation (WCF) API です。

DataAnnotations (System.ComponentModel.DataAnnotations)

.NET Native では、System.ComponentModel.DataAnnotations 名前空間と System.ComponentModel.DataAnnotations.Schema 名前空間内の型はサポートされません。 これらには、Windows 8.x 用 .NET にある以下の型が含まれます。

Visual Basic

Visual Basic は、現在 .NET Native ではサポートされません。 Microsoft.VisualBasic 名前空間と Microsoft.VisualBasic.CompilerServices 名前空間内の次の型は、.NET Native では使用できません。

リフレクション コンテキスト (System.Reflection.Context 名前空間)

System.Reflection.Context.CustomReflectionContext クラスは .NET Native ではサポートされません。

RTC (System.Net.Http.Rtc)

System.Net.Http.RtcRequestFactory クラスは .NET Native ではサポートされません。

Windows Communication Foundation (WCF) (System.ServiceModel.*)

System.ServiceModel.* 名前空間内の型は、.NET Native ではサポートされません。 これらには、次の型が含まれます。

シリアライザーの違い

DataContractSerializerDataContractJsonSerializer、および XmlSerializer クラスによるシリアル化と逆シリアル化に関する違いを次に示します。

Visual Studio の違い

例外とデバッグ

デバッガーで .NET Native を使用してコンパイルされたアプリを実行する場合、次の例外の種類について初回例外が有効になります。

アプリのビルド

Visual Studio で既定で使用される x86 ビルド ツールを使用します。 C:\Program Files (x86)\MSBuild\12.0\bin\amd64 にある AMD64 MSBuild ツールは、ビルドの問題が発生する可能性があるため、使用しないことをお勧めします。

プロファイラー

  • Visual Studio CPU プロファイラーと XAML メモリ プロファイラーでは、マイ コードのみは正しく表示されません。

  • XAML メモリ プロファイラーでは、マネージド ヒープ データが正しく表示されません。

  • CPU プロファイラーでは、モジュールが正しく識別されず、プレフィックス付きの関数名が表示されます。

単体テスト ライブラリ プロジェクト

Windows 8.x アプリ プロジェクトの単体テスト ライブラリで .NET Native を有効にすることはサポートされておらず、プロジェクトのビルドが失敗します。

関連項目