Unity 和 UWP 中遺失 .NET APIMissing .NET APIs in Unity and UWP

使用 .NET 建置 UWP 遊戲 時,您可能會發現一些您可能在 Unity 編輯器或獨立電腦遊戲中使用的 API,未出現在 UWP 上。When building a UWP game using .NET, you may find that some APIs that you might use in the Unity editor or for a standalone PC game are not present for UWP. 這是因為 UWP apps 適用的 .NET 包括每個命名空間的完整 .NET Framework 中所提供的類型子集。That's because .NET for UWP apps includes a subset of the types provided in the full .NET Framework for each namespace.

此外,部分遊戲引擎使用未與 UWP 適用的 .NET (例如 Unity 的 Mono) 完全相容的不同類型 .NET。Additionally, some game engines use different flavors of .NET that aren't fully compatible with .NET for UWP, such as Unity's Mono. 所以當您撰寫遊戲時,所有項目在編輯器中可能運作正常,但是當您移至 UWP 的建置,您可能會收到這類錯誤:命名空間 'System.Runtime.Serialization' 中沒有類型或命名空間 'Formatters' (是否遺漏了組件參考?)So when you're writing your game, everything might work fine in the editor, but when you go to build for UWP, you might get errors like this: The type or namespace 'Formatters' does not exist in the namespace 'System.Runtime.Serialization' (are you missing an assembly reference?)

幸好 Unity 提供一些這些遺失的 API 作為延伸方法和更換類型,這在通用 Windows 平台︰.NET 指令碼後端遺失 .NET 類型中有所描述。Fortunately, Unity provides some of these missing APIs as extension methods and replacement types, which are described in Universal Windows Platform: Missing .NET Types on .NET Scripting Backend. 但是,如果您需要的功能不在此處,則 .net for Windows 8. x 應用程式的總覽 將討論您可以如何將程式碼轉換為使用 WinRT 或 .net 來 Windows 執行階段 api。However, if the functionality you need is not here, .NET for Windows 8.x apps overview discusses ways you can convert your code to use WinRT or .NET for Windows Runtime APIs. (這討論 Windows 8,但也適用於 Windows 10 UWP app)。(It discusses Windows 8, but is applicable to Windows 10 UWP apps as well.)

.NET Standard.NET Standard

若要了解為何一些 API 可能無法運作,請務必了解不同的 .NET 類型,以及 UWP 如何實作 .NET。To understand why some APIs might not be working, it's important to understand the different .NET flavors and how UWP implements .NET. .NET Standard 是 .NET API 的正式規格,可跨平台和統一不同的 .NET 類型。The .NET Standard is a formal specification of .NET APIs that is meant to be cross-platform, and unify the different .NET flavors. 每個實作的 .NET 支援特定版本的 .NET Standard。Each implementation of .NET supports a certain version of the .NET Standard. 您可以在 .NET 實作支援看到標準和實作的表格。You can see a table of standards and implementations at .NET implementation support.

每個版本的 UWP SDK 符合不同層級的 .NET Standard。Each version of the UWP SDK conforms to a different level of .NET Standard. 例如,16299 SDK (Fall Creators Update) .NET Standard 2.0。For example, the 16299 SDK (the Fall Creators Update) supports .NET Standard 2.0.

如果您想要知道特定 .NET API 在您的目標 UWP 版本中是否受支援,您可以檢查 .NET Standard API 參考,然後選取該版本的 UWP 支援的 .NET Standard 版本。If you want to know if a certain .NET API is supported in the UWP version that you're targeting, you can check the .NET Standard API Reference and select the version of the .NET Standard that's supported by that version of UWP.

指令碼後端設定Scripting backend configuration

如果您建置 UWP 時遇到問題,第一件事您應該做的是檢查 [播放程式設定]([檔案] > [組建設定],選取 [通用 Windows 平台],然後 [播放程式設定])。The first thing you should do if you're having trouble building for UWP is check the Player Settings (File > Build Settings, select Universal Windows Platform, and then Player Settings). [其他設定] > [設定] 下,前三個下拉選項 ([指令碼執行階段版本][指令碼後端][Api 相容性層級]) 是所有要考慮的重要設定。Under Other Settings > Configuration, the first three dropdowns (Scripting Runtime Version, Scripting Backend, and Api Compatibility Level) are all important settings to consider.

[指令碼執行階段版本] 是 Unity 指令碼後端用來讓您取得您所選擇大致上對等版本的 .NET Framework 支援。The Scripting Runtime Version is what the Unity scripting backend uses which allows you to get the (roughly) equivalent version of .NET Framework support that you choose. 不過,請記住,並非該版本的 .NET framework 的所有 API 都支援,只有您的 UWP 目標那些 .NET Standard 版本。However, keep in mind that not all APIs in that version of the .NET Framework will be supported, only those in the version of .NET Standard that your UWP is targeting.

通常若推出 .NET 新版本,會有更多的 API 新增至 .NET Standard,讓您可以跨獨立和 UWP 使用相同的程式碼。Often with new .NET releases, more APIs are added to .NET Standard which might allow you to use the same code across standalone and UWP. 例如,System.Runtime.Serialization.Json 命名空間已導入 .NET Standard 2.0。For example, the System.Runtime.Serialization.Json namespace was introduced in .NET Standard 2.0. 如果您設定 [指令碼執行階段版本][.NET 3.5 同等](其目標是較舊版本的 .NET Standard),嘗試使用 API 時,您將會收到錯誤,請將其切換為 [.NET 4.6 同等](支援 .NET Standard 2.0),API 將可運作。If you set the Scripting Runtime Version to .NET 3.5 Equivalent (which targets an earlier version of the .NET Standard), you will get an error when trying to use the API; switch it to .NET 4.6 Equivalent (which supports .NET Standard 2.0), and the API will work.

[指令碼後端] 可以是 [.NET][IL2CPP]The Scripting Backend can be .NET or IL2CPP. 本主題中,我們假設您已選擇 [.NET],因為那是此處所討論的問題所在。For this topic, we assume you have chosen .NET, since that's where the problems discussed here arise. 如需詳細資訊,請參閱指令碼後端See Scripting Backends for more information.

最後,您應該設定 [Api 相容性層級] 為您要讓您的遊戲在上面執行的 .NET 版本。Finally, you should set the Api Compatibility Level to the version of .NET that you want your game to run on. 這應該符合 [指令碼執行階段版本]This should match the Scripting Runtime Version.

一般而言,對於 [指令碼執行階段版本][Api 相容性層級],您應該選取已推出的最新版本,以便與 .NET Framework 有更多相容性,如此可讓您使用更多的 .NET API。In general, for Scripting Runtime Version and Api Compatibility Level, you should select the latest version available so as to have more compatibility with the .NET Framework, and thus allow you to use more .NET APIs.

設定︰指令碼執行階段版本;指令碼後端;Api 相容性層級

平台相關編譯Platform-dependent compilation

如果您為多個平台 (包括 UWP) 建置 Unity 遊戲,您會想要使用平台相關編譯,以確保 UWP 用的程式碼只在遊戲建置為 UWP 時執行。If you're building your Unity game for multiple platforms, including UWP, you'll want to use platform-dependent compilation to make sure that code intended for UWP is only run when the game is built as a UWP. 如此一來,您可以對獨立的桌面和其他平台使用完整的 .NET Framework 和 UWP 適用的 WinRT API,而不會收到建置錯誤。This way, you can use the full .NET Framework for standalone desktop and other platforms, and WinRT APIs for UWP, without getting build errors.

使用下列指示詞僅在執行為 UWP app 時編譯程式碼:Use the following directives to only compile code when running as a UWP app:

#if NETFX_CORE
    // Your UWP code here
#else
    // Your standard code here
#endif

注意

NETFX_CORE 只是要檢查您是否要針對 .NET 腳本後端編譯 c # 程式碼。NETFX_CORE is only meant to check if you're compiling C# code against the .NET scripting backend. 如果您要使用不同的腳本後端(例如 IL2CPP),請 ENABLE_WINMD_SUPPORT 改用。If you're using a different scripting backend, such as IL2CPP, use ENABLE_WINMD_SUPPORT instead.

如需平台相關編譯指示詞的完整清單,請參閱平台相關編譯For the full list of platform-dependent compilation directives, see Platform dependent compilation.

常見問題和因應措施Common issues and workarounds

下列案例描述 UWP 子集遺失 .NET API 時可能發生的常見問題及其因應措施。The following scenarios describe common issues that might arise where .NET APIs are missing from the UWP subset, and ways to get around them.

使用 BinaryFormatter 資料序列化Data serialization using BinaryFormatter

遊戲通常會將儲存資料序列化,使得玩家無法輕易操縱它。It is common for games to serialize save data so that players can't easily manipulate it. 不過,BinaryFormatter 會將物件序列化為二進位,並不適用於較舊版本的 .NET Standard (2.0 之前)。However, BinaryFormatter, which serializes an object into binary, is not available in earlier versions of the .NET Standard (prior to 2.0). 請考慮改為使用 XmlSerializerDataContractJsonSerializerConsider using XmlSerializer or DataContractJsonSerializer instead.

private void Save()
{
    SaveData data = new SaveData(); // User-defined object to serialize

    DataContractJsonSerializer serializer = 
      new DataContractJsonSerializer(typeof(SaveData));

    FileStream stream = 
      new FileStream(Application.persistentDataPath, FileMode.CreateNew);

    serializer.WriteObject(stream, data);
    stream.Dispose();
}

I/O 作業I/O operations

System.IO 命名空間中的某些類型,例如 FileStream,不適用於較舊版本的 .NET Standard。Some types in the System.IO namespace, such as FileStream, are not available in earlier versions of the .NET Standard. 不過,Unity 提供 DirectoryFileFileStream 類型,您可以在您的遊戲中使用它們。However, Unity does provide the Directory, File, and FileStream types so you can use them in your game.

或者,您可以使用 Windows.Storage API,這僅適用於 UWP app。Alternatively, you can use the Windows.Storage APIs, which are only available to UWP apps. 不過,這些 API 會限制 App 寫入其特定的儲存空間,並且不提供免費存取整個檔案系統的權限。However, these APIs restrict the app to writing to their specific storage, and do not give it free access to the entire file system. 如需詳細資訊,請參閱檔案、資料夾和媒體櫃See Files, folders, and libraries for more information.

一個重要事項是 Close 方法只有在 .NET Standard 2.0 及更新版本中可用 (雖然 Unity 提供延伸方法)。One important note is that the Close method is only available in .NET Standard 2.0 and later (though Unity provides an extension method). 改為使用 DisposeUse Dispose instead.

執行緒Threading

System.Threading 命名空間中的某些類型,例如 ThreadPool,不適用於較舊版本的 .NET Standard。Some types in the System.Threading namespaces, such as ThreadPool, are not available in earlier versions of the .NET Standard. 在這些情況中,您可以改為使用 Windows.System.Threading 命名空間。In these cases, you can use the Windows.System.Threading namespace instead.

以下是如何可處理 Unity 遊戲中的執行緒,使用平台相關編譯來為 UWP 和非 UWP 平台 做準備︰Here's how you could handle threading in a Unity game, using platform-dependent compilation to prepare for both UWP and non-UWP platforms:

private void UsingThreads()
{
#if NETFX_CORE
    Windows.System.Threading.ThreadPool.RunAsync(workItem => SomeMethod());
#else
    System.Threading.ThreadPool.QueueUserWorkItem(workItem => SomeMethod());
#endif
}

安全性Security

部分 System.Security.* 命名空間,例如 System.Security.Cryptography.X509Certificates,在您建置適用於 UWP 的 Unity 遊戲時不會提供。Some of the System.Security.* namespaces, such as System.Security.Cryptography.X509Certificates, are not available when you build a Unity game for UWP. 在這些案例中,請使用 Windows.Security.* API,其涵蓋幾乎相同的功能。In these cases, use the Windows.Security.* APIs, which cover much of the same functionality.

下列範例只會取得憑證存放區中具指定名稱的憑證:The following example simply gets the certificates from a certificate store with the given name:

private async void GetCertificatesAsync(string certStoreName)
    {
#if NETFX_CORE
        IReadOnlyList<Certificate> certs = await CertificateStores.FindAllAsync();
        IEnumerable<Certificate> myCerts = 
            certs.Where((certificate) => certificate.StoreName == certStoreName);
#else
        X509Store store = new X509Store(certStoreName, StoreLocation.CurrentUser);
        store.Open(OpenFlags.OpenExistingOnly);
        X509Certificate2Collection certs = store.Certificates;
#endif
    }

如需使用 WinRT 安全性 API 的詳細資訊,請參閱 安全性See Security for more information about using the WinRT security APIs.

網路功能Networking

部分 System.Net.* 命名空間,例如 System.Net.Mail,也在建置適用於 UWP 的 Unity 遊戲時不會提供。Some of the System.Net.* namespaces, such as System.Net.Mail, are also not available when building a Unity game for UWP. 對於這些 API 大部分,請使用對應的 Windows.Networking.* 和 Windows.Web.* WinRT API 來取得類似的功能。For most of these APIs, use the corresponding Windows.Networking.* and Windows.Web.* WinRT APIs to get similar functionality. 如需詳細資訊,請參閱網路和 web 服務See Networking and web services for more information.

System.Net.Mail 的案例中,使用 Windows.ApplicationModel.Email 命名空間。In the case of System.Net.Mail, use the Windows.ApplicationModel.Email namespace. 如需詳細資訊,請參閱傳送電子郵件See Send email for more information.

另請參閱See also