Share via


將 Windows 8.x 應用程式移轉至 .NET Native

.NET Native 在 Microsoft Store 或開發人員的電腦上提供應用程式的靜態編譯。 這與 Windows 8.x 應用程式 (之前也稱為 Microsoft Store 應用程式) 在裝置上由 Just-In-Time (JIT) 編譯器或原生映像產生器 (Ngen.exe) 執行的動態編譯不同。 儘管存在差異,.NET Native 仍然試圖與 .NET for Windows 8.x 應用程式保持相容性。 大多數的情況下,在適用於 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[]

  • 在適用於 Windows 8.x 應用程式的 .NET 中,WinInet 快取並不是預設啟用的,但在 .NET Native 中則是。 這可以改善效能,但有工作集含意。 開發人員不需任何動作。

動態程式設計的差異

.NET Native 會從 .NET Framework 在程式碼中以靜態方式連結,使程式碼成為 app-local,以達到最大效能。 不過,二進位大小必須維持在較小的狀態,這樣才不會將整個 .NET Framework 帶進來。 .NET Native 編譯器使用相依性縮減程式,移除對未使用之程式碼的參照,而解除了這項限制。 不過,當該資訊無法在編譯時期靜態推斷,而是在執行階段動態擷取時,.NET Native 可能不會維護或產生某些類型資訊和程式碼。

.NET Native 確實會啟用反映和動態程式設計。 不過,並非所有類型都可以標記來進行反映,因為這樣會使所產生的程式碼大小過大 (尤其是因為可支援在 .NET Framework 中的公用 API 上反映)。 .NET Native 編譯器對於哪些類型應該支援反映進行聰明的選擇,並保留中繼資料,而且只為這些類型產生程式碼。

例如,資料繫結會要求應用程式能夠將屬性名稱對應至函式。 在適用於 Windows 8.x 應用程式的 .NET 中,通用語言執行平台會自動使用反映來提供這項功能給 Managed 類型和可公開取得的原生類型。 在 .NET Native 中,編譯器會自動為繫結資料的類型包含中繼資料。

.NET Native 編譯器也可以處理常用的泛型類型,例如 List<T>Dictionary<TKey,TValue>,這些類型不需要任何提示或指示詞即可運作。 在某些限制下,也可支援 動態 關鍵字。

注意

將您的應用程式移植到 .NET Native 時,應徹底測試所有動態程式碼路徑。

對大多數開發人員而言,.NET Native 的預設組態即已足夠,但有些開發人員可能會想要使用執行階段指示詞 (.rd.xml) 檔案來微調其組態。 此外,在某些情況下,.NET Native 編譯器會無法判斷哪些中繼資料為反映所必需,而依賴提示,尤其是下列情況:

  • 無法以靜態方式判斷某些結構,例如 Type.MakeGenericTypeMethodInfo.MakeGenericMethod

  • 由於編譯器無法判斷具現化,所以必須以執行階段指示詞來指定您想要反映的泛型類型。 這不只是因為所有的程式碼必須包含在內,也因為反映在泛型類型上會形成無限循環 (例如,在泛型類型上叫用泛型方法時)。

注意

執行階段指示詞中定義在執行階段指示詞 (.rd.xml) 檔案中。 如需使用此檔案的一般資訊,請參閱使用者入門。 如需執行階段指示詞的詳細資訊,請參閱 Runtime Directives (rd.xml) Configuration File Reference

.NET Native 也包含程式碼剖析工具,可協助開發人員決定預設集之外的哪些類型應該支援反映。

適用於 Windows 8.x 應用程式的 .NET 與 .NET Native 之間,有一些與其他個別反映相關的行為差異。

在 .NET Native 中:

不支援的案例和 API

下列各節會針對一般開發、interop 以及 HTTPClient 和 Windows Communication Foundation (WCF) 等技術,列出不支援的案例和 API:

一般開發的差異

值類型

  • 如果您覆寫 ValueType.EqualsValueType.GetHashCode 方法的值類型,請勿呼叫基底類別實作。 在適用於 Windows 8.x 應用程式的 .NET 中,這些方法會依賴反映。 在編譯時期,.NET Native 會產生不依賴執行階段反映的實作。 這表示如果您不覆寫這兩個方法,它們將會如預期般運作,因為 .NET Native 會在編譯時期產生實作。 不過,覆寫這些方法,但又呼叫基底類別實作,將會導致例外狀況。

  • 不支援大於 1 MB 的值類型。

  • 值類型在 .NET Native 中不能有無參數建構函式。 (C# 和 Visual Basic 禁止值類型上的無參數建構函式。不過,這些可以在 IL 中建立。)

陣列

泛型

  • 無限的泛型類型擴充會導致編譯器錯誤。 例如,此程式碼無法編譯:

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

指標

  • 不支援指標的陣列。

  • 您不能使用反映來取得或設定指標欄位。

序列化

不支援 KnownTypeAttribute(String) 屬性。 請改用 KnownTypeAttribute(Type) 屬性。

資源

不支援將當地語系化的資源與 EventSource 類別搭配使用。 EventSourceAttribute.LocalizationResources 屬性不會定義當地語系化的資源。

委派

不支援Delegate.BeginInvokeDelegate.EndInvoke

其他 API

  • 如果沒有將 GuidAttribute 屬性 (attribute) 套用至類型,則 TypeInfo.GUID 屬性 (property) 會擲回 PlatformNotSupportedException 例外狀況。 GUID 主要用於 COM 支援。

  • DateTime.Parse 方法會正確剖析在 .NET Native 中包含簡短日期的字串。 不過,它不會維持與日期和時間剖析中特定變更的相容性。

  • BigInteger.ToString("E") 在 .NET Native 中正確四捨五入。 在某些版本的 CLR 中,會將結果字串無條件捨去,而不是四捨五入。

HttpClient 差異

在 .NET Native 中,HttpClientHandler 類別會在內部使用 WinINet (透過 HttpBaseProtocolFilter 類別),而不是在適用於 Windows 8.x 應用程式之標準 .NET 中使用的 WebRequestWebResponse 類別。 WinINet 並未支援 HttpClientHandler 類別支援的所有組態選項。 因此:

  • HttpClientHandler 上的部分功能屬性會在 .NET Native 上傳回 false,而在適用於 Windows 8.x 應用程式的標準 .NET 上,則會傳回 true

  • 某些組態屬性 get 存取子在 .NET Native 上一律傳回固定的值,不同於適用於 Windows 8.x 應用程式的 .NET 中的預設可設定值。

下列各小節會說明一些其他的行為差異。

Proxy

這個 HttpBaseProtocolFilter 類別不支援依照每個要求設定或覆寫 Proxy 設定。 這表示 .NET Native 上的所有要求都是使用系統設定的 Proxy 伺服器,或是不使用 Proxy 伺服器,視 HttpClientHandler.UseProxy 屬性的值而定。 在適用於 Windows 8.x 應用程式的 .NET 中,是由 HttpClientHandler.Proxy 屬性來定義 Proxy 伺服器。 在 .NET Native 上,將 HttpClientHandler.Proxy 設為 null 以外的值會擲回 PlatformNotSupportedException 例外狀況。 在 .NET Native 上,HttpClientHandler.SupportsProxy 屬性會傳回 false,在適用於 Windows 8.x 應用程式的標準 .NET Framework 上,則會傳回 true

自動重新導向

HttpBaseProtocolFilter 類別不允許設定自動重新導向的數目上限。 在適用於 Windows 8.x 應用程式的標準 .NET 中, HttpClientHandler.MaxAutomaticRedirections 屬性的值預設為 50,而且可以修改。 在 .NET Native上,這個屬性的值是 10,而且嘗試修改此值會擲回 PlatformNotSupportedException 例外狀況。 在 .NET Native 上,HttpClientHandler.SupportsRedirectConfiguration 屬性會傳回 false,在適用於 Windows 8.x 應用程式的 .NET 上,則會傳回 true

自動解壓縮

適用於 Windows 8.x 應用程式的 .NET 可讓您將 HttpClientHandler.AutomaticDecompression 屬性設為 DeflateGZipDeflateGZip同時設定,或是設為 None。 .NET Native 只支援 DeflateGZip,或 None。 嘗試以無訊息模式將 AutomaticDecompression 屬性單獨設為 DeflateGZip ,會將其設為同時使用 DeflateGZip

Cookie

HttpClient 和 WinINet 會同時執行 Cookie 處理作業。 CookieContainer 所產生的 Cookie 會與 WinINet Cookie 快取中的 Cookie 合併。 從 CookieContainer 移除 Cookie 會防止 HttpClient 傳送 Cookie,但如果 WinINet 已經看到 Cookie,而且使用者沒有刪除 Cookie,WinINet 就會加以傳送。 若要使用 HttpClient, HttpClientHandlerCookieContainer API,以程式設計方式將 Cookie 從 WinINet 移除是不可能的。 將 HttpClientHandler.UseCookies 屬性設為 false 只會導致 HttpClient 停止傳送 Cookie,WinINet 還是會在要求中包含其 Cookie。

認證

在適用於 Windows 8.x 應用程式的 .NET 中, HttpClientHandler.UseDefaultCredentialsHttpClientHandler.Credentials 屬性會獨立運作。 此外, Credentials 屬性會接受實作 ICredentials 介面的任何物件。 在 .NET Native 中,將 UseDefaultCredentials 屬性設為 true 會導致 Credentials 屬性變成 null。 此外, Credentials 屬性只能設為 nullDefaultCredentials,或是 NetworkCredential類型的物件。 將任何其他 ICredentials 物件 (最常用的是 CredentialCache) 指派給 Credentials 屬性會擲回 PlatformNotSupportedException

其他不受支援或不可設定的功能

在 .NET Native 中:

Interop 的差異

已被取代的 API

有些與 Managed 程式碼交互操作的不常用 API 已被取代。 這些 API 與 .NET Native 搭配使用時,可能會擲回 NotImplementedExceptionPlatformNotSupportedException 例外狀況,會產生編譯器錯誤。 在適用於 Windows 8.x 應用程式的 .NET 中,這些 API 會標示為已過時,但是呼叫這些 API 會產生編譯器警告,而不是編譯器錯誤。

VARIANT 封送處理已取代的 API 包括:

UnmanagedType.Struct 受支援,但在某些情況下會擲回例外狀況,例如當它與 IDispatchbyref 變體一起使用時。

IDispatch 支援已取代的 API 包括:

傳統 COM 事件已取代的 API 包括:

在 .NET Native 不支援的 System.Runtime.InteropServices.ICustomQueryInterface 介面中已取代的 API 包括:

其他不受支援的 interop 功能包括:

很少使用的封送處理 API:

平台叫用和 COM interop 相容性

在 .NET Native 中,仍支援大部分的平台叫用和 COM interop 案例。 特別是仍支援與 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.DataAnnotationsSystem.ComponentModel.DataAnnotations.Schema 命名空間中的類型。 這些包括在適用於 Windows 8.x 應用程式的 .NET 中存在的以下類型:

Visual Basic

在 .NET Native 中,目前不支援 Visual Basic。 在 .NET Native 中,無法於 Microsoft.VisualBasicMicrosoft.VisualBasic.CompilerServices 命名空間中使用下列類型:

反映內容 (System.Reflection.Context 命名空間)

在 .NET Native 中不支援 System.Reflection.Context.CustomReflectionContext 類別。

RTC (System.Net.Http.Rtc)

在 .NET Native 中不支援 System.Net.Http.RtcRequestFactory 類別。

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

在 .NET Native 中,不支援 System.ServiceModel.* 命名空間中的類型。 其中包括下列類型:

序列化程式的差異

下列差異與使用 DataContractSerializerDataContractJsonSerializerXmlSerializer 類別來進行序列化和還原序列化有關。

Visual Studio 的差異

例外狀況和偵錯

當您在偵錯工具中執行使用 .NET Native 來編譯的應用程式時,會針對下列例外狀況類型啟用 First-Chance 例外狀況:

建置應用程式

使用 Visual Studio 預設使用的 x86 建置工具。 我們不建議使用 AMD64 MSBuild 工具 (可以在 C:\Program Files (x86)\MSBuild\12.0\bin\amd64 中找到);這些工具可能會造成組建問題。

分析工具

  • Visual Studio CPU 分析工具和 XAML 記憶體分析工具不會正確顯示 Just-My-Code。

  • XAML 記憶體分析工具不會準確地顯示 Managed 堆積資料。

  • CPU 分析工具不會正確地識別模組,並且會顯示具有前置詞的函式名稱。

單元測試程式庫專案

不支援為 Windows 8.x 應用程式在單元測試程式庫上啟用 .NET Native,而且這麼做會導致專案無法建置。

另請參閱