💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
* * * WINDOWS 10 2015 年特别版 # Microsoft .NET - .NET 和通用 Windows 平台开发 作者 [Daniel Jacobson](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Daniel+Jacobson) | Windows 2015 借助 Visual Studio 2015,您现在可以使用最新 .NET 技术构建运行于所有 Windows 10 设备(其中包括您口袋里的手机、背包中的笔记本电脑或平板电脑、办公室里的 Surface Hub、家里的 Xbox 控制台、HoloLens 以及您可以想象的任何其他物联网 (IoT) 设备)上的通用 Windows 平台 (UWP) 应用程序。成为 Windows 开发人员真的是太让人激动了。 ## UWP 的新增功能 作为一名 .NET 开发人员,您将会对 UWP 提供的所有功能欣喜若狂。UWP 应用将在大量已经且将继续升级至 Windows 10 的桌面上以“窗口化”模式运行。UWP 应用将能够通过一个应用程序包和一个代码库连接所有 Windows 10 设备。此外,UWP 应用还充分利用全新 Microsoft .NET Core Framework(本文后面部分有详细介绍)。您的 .NET 业务逻辑可以运行于支持 .NET Core 的其他平台,例如 ASP.NET 5。UWP 应用为应用部署一小块 .NET Core,这样应用将始终针对您测试应用所依据的 .NET 版本运行。所有 .NET UWP 应用都充分利用 .NET Native,其可生成高度优化的本机代码,从而提升性能(本文也有所介绍)。 ## .NET Core Framework .NET Core Framework 是适用于现代设备和云工作负载的新版 .NET。它是 Microsoft .NET Framework 的通用及模块化实现,可以针对各种工作负载在许多不同的环境中移植和使用。此外,.NET Core Framework 是开源代码并在 GitHub ([github.com/dotnet/corefx](http://github.com/dotnet/corefx)) 上提供,Microsoft 在 Windows、Linux 和 Mac OS X 上均提供支持。如果您是使用最新 .NET 技术的 UWP 开发人员,这对您来说将是非常大的优势。在 Visual Studio 2015 中,您可以利用 .NET Core 可移植类库 (PCL) 来锁定任意 UWP 应用、.NET 4.6 应用或 ASP.NET 5 应用(甚至那些跨平台应用)。 此外,.NET Core Framework 还是先前在 Windows 应用商店应用开发中可用的 .NET API 的超集。这就表示,UWP 开发人员现在在其 API 库中拥有其他多个命名空间。其中一个此类命名空间是 System.Net.Sockets,用于 UDP 通信。这之前在 Windows Runtime (WinRT) 应用中不可用,解决方法是使用 WinRT 特定 UDP API。由于套接字在 .NET Core 中可用,因此,您可以在 UWP 应用及其他 .NET 应用中使用相同的套接字代码。 另一大优势是,System.Net.Http.HttpClient API 构建于 WinRT HTTP 堆栈之上。这样,如果服务器支持 HTTP/2,默认情况下就可以使用它,从而降低延迟并减少来回通信。 Windows Communication Foundation (WCF) 客户端(以及关联的“添加服务引用”对话框)先前在 Windows Phone .appx 项目中不可用,但是因为它属于 .NET Core,所以可以由所有 .NET UWP 应用使用。 最后,.NET Core 是 .NET Native 依赖的基础框架。设计 .NET Native 时,很显然 .NET Framework 将不适合作为框架类库的基础。这是因为 .NET Native 静态地将框架与应用相连,然后删除应用不需要的额外内容。(这是粗略简单的介绍,但是您已经明白了。有关更多详细信息,请查看“Inside .NET Native”(.NET Native 内部),网址为 [bit.ly/1UR7ChW](http://bit.ly/1UR7ChW)。) 由于未构造传统的 .NET Framework 实现,因此,对于链接器而言,减少编译到应用中的框架量是个挑战。毕竟,.NET Core 实际上是 .NET Framework 的分支,而 .NET Framework 的实现已围绕构造问题进行了优化。该实现的另一个优势是能够将 .NET Core Framework 作为一套 NuGet 程序包进行交付,这样就可以从 .NET Framework 带外更新各个类。不过,在进一步操作之前,让我们来看看 NuGet 中的一些变化。 ## NuGet 的新增功能 对于 UWP,已内置 NuGet 3.1 支持。此版本中包括可改进程序包依赖项管理以及本地缓存程序包以便在多个项目中重用的功能。 对于 NuGet 3.1,程序包依赖项声明模型已更新。从 ASP.NET 5 开始,NuGet 引入了对 project.json 文件的支持,这是 UWP 支持的同一模型。Project.json 使您可以介绍一个项目的依赖项,清晰地定义您直接依赖的程序包。由于对于 ASP.NET 5 和 UWP 而言格式相同,因此您可以使用相同的文件定义两个平台以及 PCL 的程序包引用。 从 packages.config 更改为 project.json 使您可以在项目中“重新启动”应用,而且现在有了新的 NuGet 传递依赖项功能。如果您引用一个引用了另一 NuGet 程序包的程序包,则使用它管理包版本会比较困难。例如,NHibernate 是依赖于 lesi.Collections 的程序包。在 packages.config 中,您将会有两个引用,每个程序包一个引用。想要更新 NHibernate 时,是否也会更新 lesi.collections? 如果有适用于 lesi.collections 的更新,是否还需要更新 NHibernate 来支持新功能? 这会变成混乱的循环,程序包版本管理比较困难。NuGet 的可传递依赖项功能简化了这一决定,通过程序包定义文件 (nuspecs) 中改进的语义版本更新程序包引用。 此外,NuGet 现在可下载您使用的程序包副本并将这些程序包的副本存储在位于 %userprofile%\.nuget\packages 文件夹中的全局程序包文件夹中。这不仅可以提升程序包引用的性能(因为您将只需下载每个程序包一次),而且还会减少您工作站上所用的磁盘空间(因为您可以在项目间共享相同的程序包二进制文件)。 ## NuGet 和 .NET Core 使用注重构造的 .NET Core 并将其与 NuGet 3.1 的程序包依赖项管理结合时会如何? 您将可以从 .NET Framework 的其余部分带外更新各个 .NET Framework 程序包。对于 UWP,.NET Core 作为一套 NuGet 程序包包含在您的应用中。创建新项目时,您将只看到常规 Microsoft.NETCore.UniversalWindowsPlatform 程序包依赖项,但是如果在 NuGet 上看到此程序包,您将会看到包含的所有 .NET Framework 库,如图 1 所示。 ![](https://box.kancloud.cn/2016-01-08_568f406da9da6.png)  图 1 查看 NuGet 中的 .NET Framework 库 例如,假设存在引入您喜欢在应用程序中使用的新 API 的 System.Net.Sockets 类的更新。对于传统的 .NET,您的应用需要依赖于整个 .NET Framework 的新版本。对于 UWP 和具有 NuGet 的 .NET Core,您可以将 NuGet 依赖项更新为包含该程序包的最新版本即可。然后,编译和打包您的应用程序时,该版本的框架库将包含在您的应用程序中。这样一来,您便可以灵活地使用最新且最强大的 .NET 技术,而不用迫使用户始终在其设备上安装最新的框架。 除了能够根据您自己的节奏更新 .NET 类之外,.NET Core 的组件化特征还能使 .NET Native 在交付到用户设备时为所有 Windows 10 C# 和 Visual Basic 应用程序带来性能优势。 ## 什么是 .NET Native? 现在,您已经了解 .NET Core Framework 实现了 .NET Native,接下来我将为您详细介绍什么是 .NET Native 及其可为 UWP 开发人员提供哪些功能。 .NET Native 是一种预先 (AOT) 编译过程,其在编译时将您的托管 .NET 代码转变为本机代码。相反,传统的 .NET 则采用实时 (JIT) 编译,这会延迟方法的本机编译,直到其在运行时首次执行。.NET Native 更类似于 C++ 编译器。事实上,它采用 Visual Studio C++ 编译器作为其工具链的一部分。每个托管的(C# 或 Visual Basic)通用 Windows 应用都将利用这一新技术。应用程序会在到达用户设备之前自动编译为本机代码。如果您想深入了解其工作原理,我强烈建议您阅读 MSDN 库文章“Compiling Apps with .NET Native”(使用 .NET Native 编译应用),网址为 [bit.ly/1QcTGxm](http://bit.ly/1QcTGxm)。 ## .NET Native 为您及您的应用带来哪些影响? 获得的好处可能不尽相同,但是大多数情况下,应用启动速度会变快、性能会更出色且占用的系统资源会更少。预计首次启动应用程序时其性能会提升 60%,后续启动(“热”启动)则会实现高达 40% 的性能提升。进行本机编译时,应用程序会占用更少的内存。.NET 运行时的所有依赖项都会被删除,所以最终用户将永不需要跳出安装体验过程即可获得您应用所引用的特定 .NET Framework 版本。事实上,所有 .NET 依赖项均打包在您的应用程序内,所以您应用的行为不会因计算机上安装的 .NET Framework 有变化而发生变化。 即使您的应用程序正编译为本机二进制文件,您仍可利用您熟悉的 .NET 语言(C# 或 Visual Basic)以及关联的出色工具。最后,您可以继续使用 .NET Framework 提供的全面且一致的编程模型,它具有面向业务逻辑、内置内存管理以及异常处理的广泛 API。 有了 .NET Native,您在以下两个方面均实现最优化:托管的开发和 C++ 性能。这多酷啊! ## 调试与发布编译配置 .NET Native 编译是一个复杂的过程,这就使得其比经典 .NET 编译要慢一点。前面提到的优势都是以牺牲编译时间为代价的。每次要运行应用时您都可以选择本机编译,但是您将会花费额外的时间来等待生成完成。Visual Studio 工具旨在解决这一问题,以及打造尽可能顺畅的开发体验。 在“调试”配置中构建并运行时,您将针对应用程序内打包的 CoreCLR 运行中间语言代码。.NET 系统组件与您的应用程序代码一起打包,您的应用程序将依赖于 Microsoft.NET.CoreRuntime (CoreCLR) 程序包。如果您正在测试的设备缺少 CoreCLR 框架,则在部署您的应用程序之前,Visual Studio 将自动检测并进行安装。 这意味着您可以获得尽可能出色的开发体验:快速编译和部署、丰富的调试与诊断以及您习惯用于 .NET 开发的所有工具。 切换至“发布”模式时,默认情况下,您的应用会利用 .NET Native 工具链。因为程序包编译到本机二进制文件,所以程序包不需要包含 .NET Framework 库。而且,程序包依赖于最新安装的 .NET Native 运行时(与 CoreCLR 程序包相反)。设备上的 .NET Native 运行时将始终与您的应用程序包兼容。 通过“发布”配置进行的本地本机编译将支持在与您客户将体验的环境类似的一种环境中测试您的应用程序。要继续进行开发,定期进行该测试非常重要! 通过使用您的客户将体验的代码生成和运行时技术测试您的应用程序,您将可以确保解决所有可能的 bug(例如由于不同性能特点导致的潜在争用条件)。 一个很好的经验法则就是,在开发过程中定期对您的应用进行这一测试,以确保发现并纠正 .NET Native 编译器可能会导致的任何问题。大多数情况下,不会有问题;但是,仍会有一些与 .NET Native 不太兼容的条目。4+ 维数组就是个例子。最终,您的客户将会获得您的应用程序的 .NET Native 编译版本,所以在开发过程中以及发运之前对该版本进行测试始终是个好的做法。 除了测试 .NET Native 编译,您可能还会注意到 AnyCPU 生成配置消失了。有了 .NET Native,AnyCPU 不再是有效的生成配置,因为本机编译依赖体系结构。另一个结果就是,在您打包应用程序时,应选择全部三个体系结构配置(x86、x64 和 ARM)以确保您的应用程序尽可能适用于更多的设备。这毕竟是通用 Windows 平台。 这么说来,您仍可以构建要在您的 UWP 应用中引用的 AnyCPU 库和 DLL。这些组件将基于使用它的项目 (.appx) 的配置编译到特定于体系结构的二进制文件中。 ## 云中的 .NET Native .NET Native 一个强大的功能就是编译器可以托管在云中。这意味着,当对编译器进行可能会对您的应用程序产生有益影响的改进后,应用商店的云托管 .NET Native 编译器可以重新编译您的应用程序包来获取这些优势。每次完成此编译后,对于您这个开发人员都将是透明的,但是,最终都是应用程序用户更幸福。 不过,这会对您的工作流程产生一些影响。例如,确保您始终安装最新的工具是很好的想法,这样您就可以针对最新本地版本的编译器测试您的 .NET Native 编译。此外,在 Visual Studio 中构建您的应用商店程序包时,会创建两个程序包:一个是 .appxupload,一个是 “test”.appx,用于旁加载。.appxupload 包含 MSIL 二进制文件,以及对您应用使用的 .NET Native 工具链版本的显式引用(在 AppxManifest.xml 中引用为“ilc.exe”)。之后,该程序包进入应用商店并使用相同的 .NET Native 工具链版本对其进行编译。因为编译器是云托管编译器,所以它可以循环修复 bug,而不用您本地重新编译应用。 使用 .NET Native 时,您必须谨慎对待上传至应用商店的程序包。因为应用商店为您执行本机编译,所以您不能上传本地 .NET Native 编译器生成的本机二进制文件。Visual Studio 工作流将指导您完成该过程,以便您选择正确的程序包。有关创建应用商店程序包的全面指导,请查看 MSDN 库文章“Packaging Universal Windows Apps for Windows 10”(打包 Windows 10 的通用 Windows 应用),网址为 [bit.ly/1OQTTG0](http://bit.ly/1OQTTG0)。该文章将指导您完成程序包创建过程,以确保您生成并选择要上传至商店的正确程序包。 ## 使用 .NET Native 调试 如果您发现应用程序中某些问题可能是由 .NET Native 所导致,您可以使用一项技术来帮助调试该问题。默认情况下,发布配置全面优化代码(例如,在很多地方应用的代码内联),这会丢失一些调试项目。因此,尝试调试发布配置应用会很困难;您可能会遇到预料不到的步进和断点行为,并且由于内存优化而无法检查变量。因为发布配置的默认行为是使用代码优化的 .NET Native 编译器,所以很难调试可能是由 .NET Native 编译过程导致的任何问题。 一个很好的解决办法是,为采用 .NET Native 编译器但未全面优化代码的项目创建自定义生成配置。要创建自定义生成配置,请从版本配置下拉菜单中打开“配置服务器”,如图 2 所示。 ![](https://box.kancloud.cn/2016-01-08_568f406db9fd9.png)  图 2 打开配置服务器 在“活动”解决方案配置下拉菜单中,选择“”创建新配置,如图 3 所示。 ![](https://box.kancloud.cn/2016-01-08_568f406dcc498.png)  图 3 新建配置 为新配置提供日后对您有用的名称。我想使用“Debug .NET Native”。 从“发布”生成配置中复制设置,然后单击“确定”。 关闭配置管理器,通过右键单击解决方案资源管理器中的项目并单击“属性”来打开项目的属性页。导航到“生成”选项卡并确保选中“使用 .NET Native 工具链编译”,而且取消选中“优化代码”,如图 4 所示。 ![](https://box.kancloud.cn/2016-01-08_568f406ddec2e.png)  图 4 为调试 .NET Native 创建生成配置 现在,您拥有可用于调试 .NET Native 特定问题的生成配置。 有关使用 .NET Native 进行调试的详细信息,请参阅 MSDN 库文章“Debugging .NET Native Windows Universal Apps”(调试 .NET Native Windows 通用应用),网址为 [bit.ly/1Ixd07v](http://bit.ly/1Ixd07v)。 ## .NET Native Analyzer 当然,了解如何调试问题挺好的,但是能从一开始就避免问题岂不是更好? Microsoft.NETNative.Analyzer ([bit.ly/1LugGnO](http://bit.ly/1LugGnO)) 可以通过 NuGet 在您的应用程序中安装。通过程序包管理器控制台,您可以使用下列命令安装程序包: Install-Package Microsoft.NETNative.Analyzer。开发时,如果您的代码与 .NET Native 编译器不兼容,该分析器将会为您发出警告。有一小部分 .NET 接口不兼容,但是对于大多数应用而言,这根本不是问题。 ## 结束语 综上所述,成为 .NET Windows 开发人员是多么令人激动的事情啊!凭借 UWP、.NET Native 以及对 NuGet 的更改,跨这么多客户喜爱的不同设备创建应用从未如此简单。您将有史以来第一次可以充分利用任何 .NET 类的最新进步,并且依然期望您的应用程序能够在所有 Windows 10 设备上运行。 * * * Daniel Jacobson *是 Visual Studio 的程序管理员,致力于研究面向 Windows 平台开发人员的工具。您可以通过 [dajaco@microsoft.com](mailto:dajaco@microsoft.com) 与他联系。*