Unity 和 UWP 中缺少 .NET API

使用 .NET 生成 UWP 游戏时,你可能会发现在 Unity 编辑器或独立电脑游戏中可能用于 UWP 的某些 API 不存在。 这是因为适用于 UWP 应用的 .NET 包含每个命名空间的完整 .NET Framework 中提供的类型的子集。

此外,某些游戏引擎使用不同的 .NET 风格,这些版本与适用于 UWP 的 .NET 完全兼容,例如 Unity 的 Mono。 因此,在编写游戏时,所有内容在编辑器中可能都正常工作,但是当你为 UWP 进行生成时,你可能会收到如下错误: 命名空间“System.Runtime.Serialization”中不存在类型或命名空间“格式化程序”(你缺少程序集引用吗?

幸运的是,Unity 提供了其中一些缺少的 API 作为扩展方法和替换类型,通用 Windows 平台:.NET 脚本后端上缺少 .NET 类型。 但是,如果你需要的功能不在此处,则适用于 Windows 8.x 应用的 .NET 概述中讨论了可转换代码以使用适用于 Windows 运行时 API 的 WinRT 或 .NET 的方法。 (它讨论了 Windows 8,但也适用于 Windows 10 UWP 应用。

.NET Standard

若要了解某些 API 可能不起作用的原因,请务必了解不同的 .NET 风格以及 UWP 如何实现 .NET。 .NET Standard 是 .NET API 的正式规范,旨在跨平台,并统一不同的 .NET 风格。 .NET 的每个实现都支持特定版本的 .NET Standard。 可以在 .NET 实现支持中看到标准和实现表。

UWP SDK 的每个版本都符合不同级别的 .NET Standard。 例如,16299 SDK(Fall Creators Update)支持 .NET Standard 2.0。

如果想要知道目标 UWP 版本中是否支持特定 .NET API,可以检查 .NET Standard API 参考 ,并选择该版本的 UWP 支持的 .NET Standard 版本。

编写后端配置的脚本

如果你在针对 UWP 进行生成时遇到麻烦,首先应该检查“播放器设置”(“文件”>“生成设置”,并依次选择“通用 Windows 平台”和“播放器设置”)。 在“其他设置”>“配置”下,前三个下拉列表(脚本运行时版本、脚本后端和 API 兼容性级别)都是需要考虑的重要设置。

脚本 运行时版本 是 Unity 脚本后端使用的内容,可用于获取所选的 .NET Framework 支持(大致)等效版本。 但是,请记住,并非所有 .NET Framework 版本中的 API 都受支持,只有 UWP 面向的 .NET Standard 版本中的 API。

通常,使用新的 .NET 版本,更多的 API 会添加到 .NET Standard 中,这样就可以跨独立和 UWP 使用相同的代码。 例如, System.Runtime.Serialization.Json 命名空间是在 .NET Standard 2.0 中引入的。 如果将脚本运行时版本设置为 .NET 3.5 等效版本(面向早期版本的 .NET Standard),则在尝试使用 API 时会收到错误;将其切换到 .NET 4.6 等效版本(支持 .NET Standard 2.0),API 将正常工作。

脚本 后端 可以是 .NETIL2CPP。 对于本主题,我们假设你选择了 .NET,因为这是此处讨论的问题所在。 有关详细信息,请参阅脚本后端。

最后,应将 Api 兼容性级别 设置为要运行游戏的 .NET 版本。 这应与脚本运行时版本匹配

通常,对于 脚本运行时版本API 兼容性级别,应选择可用的最新版本,以便与 .NET Framework 更兼容,从而允许使用更多 .NET API。

配置:编写运行时版本的脚本;编写后端脚本;API 兼容性级别

依赖于平台的编译

如果要为多个平台(包括 UWP)构建 Unity 游戏,则需要使用依赖于平台的编译来确保仅当游戏生成为 UWP 时,才运行适用于 UWP 的代码。 这样,便可以将完整的 .NET Framework 用于独立桌面和其他平台,以及适用于 UWP 的 WinRT API,而不会收到生成错误。

使用以下指令仅在作为 UWP 应用运行时编译代码:

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

注意

NETFX_CORE 仅用于检查是否针对 .NET 脚本后端编译 C# 代码。 如果使用其他脚本后端(如 IL2CPP),请改用 ENABLE_WINMD_SUPPORT

常见问题和解决方法

以下方案描述了在 UWP 子集中缺少 .NET API 以及绕过 .NET API 的方法时可能出现的常见问题。

使用 BinaryFormatter 进行数据序列化

游戏通常序列化保存数据,以便玩家无法轻松操作这些数据。 但是, 将对象序列化为二进制的 BinaryFormatter 在早期版本的 .NET Standard 中不可用(低于 2.0)。 请考虑改用 XmlSerializerDataContractJsonSerializer

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 操作

System.IO 命名空间中的某些类型(如 FileStream)在早期版本的 .NET Standard 中不可用。 但是,Unity 确实提供目录文件和 FileStream 类型,以便你可以在游戏中使用它们。

或者,可以使用 仅适用于 UWP 应用的 Windows.Storage API。 但是,这些 API 将应用限制为写入其特定存储,并且不授予应用对整个文件系统的免费访问权限。 有关详细信息,请参阅 文件、文件夹和库

一个重要注意事项是, Close 方法仅在 .NET Standard 2.0 及更高版本中可用(尽管 Unity 提供了扩展方法)。 请改用 Dispose

线程处理

System.Threading 命名空间中的某些类型(如 ThreadPool)在早期版本的 .NET Standard 中不可用。 在这些情况下,可以改用 Windows.System.Threading 命名空间。

下面介绍如何在 Unity 游戏中处理线程处理,使用依赖于平台的编译为 UWP 和非 UWP 平台做好准备:

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

安全性

些 System.Security。* 生成适用于 UWP 的 Unity 游戏时,命名空间(如 System.Security.Cryptography.X509Certificates)不可用。 在这些情况下,请使用 Windows.Security。* API,其中涵盖了许多相同的功能。

以下示例仅从具有给定名称的证书存储中获取证书:

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 的详细信息,请参阅 安全性

网络

有些 System.Net.* 命名空间(如 System.Net.Mail)在为 UWP 生成 Unity 游戏时同样不可用。 对于其中大多数 API,请使用相应的 Windows.Networking。* 和 Windows.Web。* 用于获取类似功能的 WinRT API。 有关详细信息,请参阅 网络和 Web 服务

对于 System.Net.Mail,请使用 Windows.ApplicationModel.Email 命名空间。 有关详细信息,请参阅 发送电子邮件

另请参阅