.Net Core、Portable、Standard、Compact、UWP和PCL之间的区别是什么?

51
我听说过以下几种与编程有关的内容:
.Net Core、.Net Portable、.Net Standard、.Net Compact、Universal Windows Platform和Portable Class Libraries。这些都被解释为“完整 .Net 的子集,允许你针对多个平台进行开发”。那么我的问题是:
1.它们之间有什么区别?
2.如果我想编写一个可用于尽可能广泛的受众的库,我需要使用哪一个(或多个)?
"My specific situation: 我有一个针对 .Net 2.0、.Net 4.5 和 UWP 的。为了支持 UWP,我需要创建一个新的VS项目并链接所有现有文件,这是一个巨大的痛苦。现在有人告诉我它不适用于PCL,听起来我必须再次为 .Net Standard 做一遍?"

1
这里有一篇详细的讨论 链接在此 - Peter Torr - MSFT
2
你忘了.NET Micro了。我的意思是,现在并不太多的人关心它,但只要我们的目标是完整性,并且还提到了Compact... - Jeroen Mostert
如果可以的话,请使用.NET Core(但请注意,除非您的库很简单,否则您将需要花费时间重写一些内容),如果不能,请使用.NET Framework 2.0,如果不能并且需要对async/await进行单独支持,请使用.NET 4.5 Framework。.NET Compact已经死亡,.NET Micro快要死亡,Core取代了PCL(= .NET Portable),UWP是Windows Store的.NET,.NET Standard试图统一.NET Core和.NET Framework,但仍有很长的路要走才能不让人感到困惑。这是我的个人TL;DR,但我必须说,您为一个好答案提供300分是完全正确的。 - Jeroen Mostert
1
更加令人困惑的是,几乎没有一篇文章能够清晰地区分平台(UWP、Mono、CLR、.Net Core、.NET Native以及各种手机/嵌入式版本)、构建技术(MSBuild、.NET Core、.NET Native)和运行库集(BCL、Silverlight、UWP、.NET Core、.NET Native)。并非所有组合都存在。.NET Standard试图通过库来标准化,但故意将平台和构建技术留给您从其他方面解决。随着.NET Core的成熟和取代其他技术,这种混淆应该会减少,但这还需要一段时间。 - Jeroen Mostert
".NET Native" 或许是一个更好的名称,用来代替通用 Windows 平台,因为你似乎专注于应用程序开发中 .NET Framework 的方面。 - G. Stoynev
显示剩余3条评论
3个回答

55

我先回答你的第二个问题:

我有一个库,可以针对 .Net 2.0、.Net 4.5 和 UWP 进行开发。为了支持 UWP,需要创建一个新的 VS 项目并链接所有现有文件,这是非常困难的。现在有人告诉我它不适用于 PCL,听起来好像我还需要为 .Net Standard 再做一次类似的操作?

如果我想编写一个能够被尽可能多的人使用的库,我需要使用哪一个(或多个)?

简短回答:你应该针对 netstandard 进行开发。使用具有你需要的所有 API 的最低版本。你可以使用像API Port这样的工具来检查你现有的项目与给定的netstandard版本的兼容性

不幸的是,这种方法将把更旧的平台留在后面,比如你的情况下是 .NET 2.0。如果必须保持 .NET 2.0 的支持,则需要一个单独的项目(带有链接文件),以构建单独的 .NET 2.0 程序集。

接下来是细节...

有什么区别!?

  • .Net Standard (netstandard) - 这是新的跨平台 BCL API。它是一个“标准”,因为它只是一个 API 定义,而不是一个实现。这样做的想法是,你可以将你的库编译为(一个版本的)这个 API,并在支持该版本的任何平台上运行它。
  • .Net Core - 可以将其看作是netstandard的参考实现(带有一些额外的功能)。它是该API的跨平台实现。虽然可能会有用户界面和其他框架构建在其之上,但目前其仅确保的用途是作为ASP.NET Core的首选平台。[旁注:由于历史原因,“.NET Core”与netcore NuGet目标完全不同;在NuGet上下文中,netcore表示“Windows 8/8.1/10”]
  • .Net PortablePortable Class Libraries - 可移植类库(PCLs)是提供跨平台API的一种最小公共多数方法。它们覆盖了广泛的目标平台,但它们不完整且不具备未来支持性。它们已经被netstandard所取代。
  • .Net Compact - 这是一个完全不同的.NET框架,具有自己独特的API。它与任何其他框架、PCL或netstandard版本完全不兼容;因此,它比任何其他平台都更难以支持。但是,它仍然用于内存限制严格的设备上。
  • Universal Windows Platform - 这是Win10时代将Windows Phone和桌面API合并的结果,允许编写适用于两个平台的Windows Store应用程序/库。它已经被netstandard所取代。

2
其他用户的回答都很长,我觉得把赏金给最短的回答(而且是一个不需要声望值的用户)有点不好意思。但是考虑到这是最完整和最简洁的答案,它绝对值得。谢谢Stephen! - BlueRaja - Danny Pflughoeft
对于今天可以使用的最具可移植性的代码,PCL 是最合适的选择吗? - Kip Morgan
@KipMorgan:仅适用于旧平台。再过一两年,答案将是“绝对不”。 - Stephen Cleary
@StephenCleary 我刚刚安装了.NET Core 2.0 SDK,现在正在尝试使用它。我注意到没有PCL选项,这是因为.NET Core是netstandard的实现,而netstandard应该替换PCL吗?如果是这种情况,那么.NET Core Class Library能否像PCL一样部署在移动应用程序上? - Halter
Xamarin是移动端的“未来方向”。任何netstandard库都可以在最新版本的Xamarin上运行。如果您所说的“移动”指的是其他内容,则:UWP支持netstandard1.4及以下版本,WPA支持netstandard1.2及以下版本,而WP-SL仅支持netstandard1.0。.NET Core类库只能在.NET Core(Windows / Linux,而非移动设备)上运行。 - Stephen Cleary

23
作为评论中提到的,微软已经有一份描述了所有这些信息的文档。但是,根据您的回复,似乎您并没有完全理解整个内容。这篇文档非常长,所以以下是(希望)简短易懂的版本。
我们将从上面链接中的以下表格开始,希望这能消除一些困惑:

.NET Standard compliance

以下是一份简要概述,供后来者参考:.NET库在其15年的存在期间已经经历了许多变化和移植。在此期间,许多智能手机现在几乎与2001年使用的某些台式机一样强大。在这个过程中,为了在不同平台上使用,创建了.NET框架的子集(并很快被放弃)。随着Satya Nadella将.NET打造成尽可能广泛的平台的新方法,事情需要改变。

作为一项已有15年历史的技术,需要进行改进。自2014年以来,.NET Core作为.NET架构的完全革新版一直在进行开发。它是从头开始重写的.NET语言的新版本。Core的目标之一是实现跨平台部署。无论是要在iPhone/Android/XBox One上运行的应用程序,还是要在IIS上托管或在Linux盒子上运行的网站,.NET Core都可以胜任。它通过多种方式实现这一点,包括不需要在计算机上安装.NET Framework,而是将必要的库与您的解决方案一起打包。
最值得注意的是,ASP.NET发生了巨大变化。旧的System.Web已经完全消失,并被重新编写为尽可能高效并获得令人印象深刻的结果。独立的WebApi控制器已经消失,因为所有工作都在单个控制器中完成。整个过程现在是选择加入而不是默认允许您可能不想要的功能。
然而,作为开发人员,我们最终会想要迁移某些应用程序,那么我们如何确保我们已经编写的代码没有对方法进行多次小的名称更改,从而破坏了庞大解决方案的编译? 这就是 .NET Standard 的作用。这是一组必须实现的 API,以便您的平台称其为 ".NET"。
由于我们多年来一直在使用的基本 .NET Framework 已经得到了很好的建立,因此它被用作标准将包含的基础。然而,并非所有内容都包括在内,因为这有什么意义呢? 因此,标准只是各种类型的 .NET 平台之间存在的常见 API。你最终不会在 ".NET Standard" 中编写代码。

Xamarin(包含在上表中)于2016年被微软收购,该技术被用于帮助构建(或至少启发).NET Core实现跨平台。它仍然存在作为一个工具,但是与过去使用的方式相同。根据表格,在vNext版本中,它将符合.NET Standard 2.0标准。然而,它的目标受众不会改变。

直接回答你的问题,如果你想编写一个具有最广泛的单一部署解决方案的应用程序,你应该使用.NET Core。然而,如果你正在使用当前基于.NET Framework 2.0和4.5构建的库,则必须使用.NET Framework并具有针对该目标的单独UWP解决方案。

如果它提供了可以通过Web API调用的内容,你可以在.NET Framework上运行它,并在.NET Core中拥有一个单一的解决方案来部署到最终用户。如果它集成到你的代码中,除非提供.NET Core更新,否则你将不幸地无法使用。

希望这能够消除不同技术名称之间的混淆。
编辑
在了解您具体情况后,我可以为您澄清一些事情。您不能创建一个既针对.NET Framework又针对.NET Core的单一解决方案。它们以完全不同的方式编译,使用不同的基础技术,因此这与尝试在.NET 2.0解决方案中使用.NET 4.5版本相同。
但是,有一些tutorials可以让您将项目移植到Core。大多数情况下,只需将类主体复制到您的.NET Core解决方案中,大部分内容都将正常工作。有些部分已经被放弃,有些部分还没有完全成熟(例如,Entity Framework并没有所有相同的功能)。也有一些调用发生了一些变化。
好消息是,从现在开始,.NET Core将为您提供最广泛的覆盖范围。.NET Framework不会消失,但它和Core将更加同步。
.NET Core的另一个好处是采用迭代式部署方法,因此您不必等待2年才进行下一次重大升级。通过NuGet提供所有内容,您将更快地获得改进和新功能。

@BlueRaja-DannyPflughoeft:你的库是否有任何条件代码,使其在.NET 4.5上执行某些操作而在.NET 2.0上不执行?如果没有,那么您可以将.NET 4.5从需要关注的平台选择列表中划掉,因为任何.NET 2.0库都可以在.NET 4.5上正常工作,无需进行二进制更改。(除了一些次要更改,如果它们对您很重要,已经被条件代码覆盖。) - Jeroen Mostert
@JeroenMostert 是的 - BlueRaja - Danny Pflughoeft
@Alex 正确。UWP是那些没有大兄弟们所有功能的“子集”之一。 - krillgar
1
直接回答你的问题,如果你想编写一个具有最广泛的单一部署解决方案的应用程序,你应该使用.NET Core。我曾经认为.NET Core是所有.NET版本的最常见分母。然而,事实并非如此。也就是说,并没有功能性的“核心”可以在目前存在的所有.NET平台上使用,我不能创建一个“统治它们所有”的单一库,对吗?例如,我必须在所有地方使用Socket,但在UWP中使用StreamSocket。 - Alex
1
@Alex 很遗憾,除非你想用 IL 写它,否则没有办法编写一个可以被每种类型的框架使用的库。 - krillgar
显示剩余4条评论

22
我假设您已经阅读了微软的文章,并且通过其中的表格一切都变得清晰易懂。如果是这样,那么您和我之前在花费大部分下午研究此问题(并尝试将我的反射库移植到.NET Core,这也是我唯一的.NET Core移植工作)之前处于同一条船上。以下不是官方立场,而是我通过大量阅读以及作为.NET 1.0开发人员所发现的个人总结。我无法保证其完全准确(特别是涉及移动开发方面,我几乎一无所知),欢迎指正。如果有很多错误,我会将其变成维基百科。
我将按照时间顺序逐步介绍,因为我发现这样最有意义,如果您想了解旧版和新版之间的关系。它可能需要大幅简化,但目前我没有时间这样做。然而,在结尾处确实有一个TL;DR版本。

漫长而曲折的道路

尽管.NET起源于Java,但它从未真正试图成为“编写一次,随处运行”。它最初非常在Windows阵营中,并且即使它编译成字节码并没有过度使用显式的Windows操作系统相关代码,因此理论上非常易移植,但这并不是微软真正感兴趣的。.NET Framework的一部分早期开源,一群开源爱好者接手并运用它,给我们带来了Mono。Mono很重要,因为它是.NET的第一个替代平台和库集,并且说明了平台与库集与工具链的思想。Mono试图提供(更或多或少)完整的公共语言运行时及其关联的基础类库实现。这很重要:尽管Mono在Linux(和其他一些Unix系统)上运行,但它不是一个单独的平台,因为它实现了(某些版本的)CLR + BCL。对于应用程序开发人员而言,存在运行时差异(路径名等),但对于实际的库编程,您可以将Mono和Windows的.NET Framework视为具有稍微不同实现的“相同”平台。我强调这一点,因为我们将遇到针对Windows的.NET代码,该代码没有在CLR上运行,因此更难进行移植(无论是否具有讽刺意味)。

接着出现了Windows Phone(多个版本),Windows CE(多个版本),Windows Embedded CE,Windows Toaster(好吧,这个并不存在),每次基本上都会重新发明一些 .NET 的味道,但是运行时和/或 BCL 中的基础内容会缺失或更改。这就是我们得到.NET Compact.NET MicroWindows Phone(旧版,没有单独的框架名称)和Silverlight的地方。所有这些都应该被视为类似于 .NET Framework 的独立平台 + 库组合,从而使跨平台开发成为可能,但与它不同的是,使其不那么容易。由于跟踪支持的位置变得最不方便,因此有人想出了 可移植类库 以及它们的相关配置文件(它们的集合称为.NET Portable 参考程序集)。

基本上,您需要针对一组特定的.NET版本、平台(和库)进行目标设置,然后您将获得模仿这些组合的参考程序集以进行编译。根据您明确希望针对哪些风味,存在许多不同的配置文件。这是 .NET Standard 现在试图在更大范围内尝试的第一次尝试。基本上,除非您针对 .NET Standard 不支持的内容,否则 PCL 已经过时。.NET Standard 摆脱了无数不同配置文件的想法,这很好,但代价是削减了您的库可以较早地针对的一些内容,这是不好的。有在线资源可帮助从 PCL 过渡到 .NET Standard。如果您现在正在查看可移植代码,则不要专注于 PCL,除非您真的想支持一些相当边缘的平台(不打算冒犯仍在为它们开发的人)。 通用 Windows 平台,顾名思义,是一个平台。具体来说,它是由 Windows 应用商店(包括桌面和手机应用)支持的 .NET 平台。仅此而已,没有更多,也没有更少。最好视为 Silverlight 的自然继承者,因为它是一个沙盒化框架,支持桌面和移动设备。尽管名字叫做“通用”,但它并不是你想要让所有代码都针对的平台。它是一个你可能希望为你的代码启用的平台,并且独特之处在于它是我所知道的唯一一个具有相同版本中两个运行时的平台。马上就来! .NET Native在原帖中没有提到,但在这些讨论中经常出现,因为它和.NET Core一样是新的,并且听起来非常性感,因为它可以直接将.NET编译成机器代码(预先编译,而不是JIT编译)。它不是一个完全新的平台,而是用于UWP应用程序的新运行时(仅限于这些应用程序在发布模式下编译时使用)。在调试模式下,它们使用CoreCLR(即.NET Core运行时)。除非你真的想构建一个UWP应用程序,否则你不需要过多考虑这个问题,因为在.NET Native中,反射方面有很多有趣的事情需要开发人员单独关注。

现在我们来谈一下.NET Core! .NET Core最初是作为“ASP.NET Core”开始的,但人们很快意识到它可以比那更大。.NET Core是一个新的运行时(CoreCLR)+库组合,具有明确的跨平台支持(即跨操作系统)。与CLR + BCL组合不同,其中Windows版本和Unix版本以Mono的形式存在,.NET Core是所有平台的一个代码库(当然,还有通常的特定于平台的细节以支持蓬松的可移植层上方)。进一步让人困惑的是,.NET Core也是一种新的工具链/项目类型,用于支持构建.NET Core应用程序,在此之前我们只有MSBuild。这是因为Linux没有Visual Studio,所以必须这样做,但微软已经在摆脱这种“让它简单且使用JSON”的方法,转而回归到一个通用格式同时支持.NET Framework和.NET Core(它将是MSBuild,因为有更多的依赖于它)。

.NET Core在很大程度上与.NET Framework兼容。因此,如果您的.NET Core应用程序实际上在.NET Framework(在Windows上)上运行,它可以加载针对.NET Framework而不仅仅是.NET Core的程序集。这是混淆和不可移植代码的重要原因:虽然您可以构建并加载这些程序集,但它们会使您的代码不可移植。.NET Core本身不会阻止您这样做;.NET Standard(即将推出)将在正确对齐声明的情况下才能阻止。

跟上了吗?很好,因为现在我们准备向你介绍.NET Standard。.NET Standard不是一个平台(不能下载安装到机器上),也不是一个库(但有支持它的包用于构建目的),它是一个档案。它试图标准化刚才讨论过的各种事物的库表面。其想法是,如果您的代码针对.NET Standard X.Y,您只需要将构建工具切换到“请给我.NET Standard X.Y”,并构建您的程序集时,您可以确信它将可用于由X.Y覆盖的所有平台。太棒了!世界又简单了!

“现在还不是这样。问题在于,.NET Core目前正在进行大量开发,这意味着很多东西都缺失或不同——甚至是非常基础的东西,在您的.NET Framework代码库中可能自然存在,比如将异常标记为Serializable并为其提供一个单独的构造函数以进行反序列化,以便它们可以在AppDomain之间良好地工作。.NET Core中没有AppDomain,因此没有序列化,因此这些构造函数将无法编译。即使Serializable属性本身在旧版本的CoreCLR中也不可用。如果您的MSBuild项目使用自定义目标,那就太糟糕了,.NET Core工具链目前不支持该功能(当它再次成为MSBuild时,可能会有支持)。当然,您可以重写,但无法重用。因此,虽然您可以针对.NET Standard,但您可能需要两个单独的项目和/或一些条件编译来获取适用于两个不同平台的.NET Standard程序集。如果你幸运(或可以妥协一点),你的库足够简单,只使用.NET Core构建就足够了。不要误解:仍然存在多个.NET平台,它们仍然有差异,.NET Standard只是试图使移植更加容易。到目前为止,它的功能有限,但已经比PCL做得更好了。”
简而言之:.NET Core和.NET Framework(以及它们的所有小表亲)在概念上和实现上都是不同的平台。.NET Standard是一种目标框架,可以简化在它们之间移植代码所需的工作(但还不能完全透明)。PCL是Standard的前身,如果你是进步的话可以忽略它。

TL;DR从这里开始(但仍然很长)

最终回答你的问题,如果你是一名现代图书馆开发人员,并且想要面向“尽可能多的受众”,那么你应该做什么呢?首先,如果可能的话,你必须缩小目标范围。你会明确支持和测试哪些平台?你真的想在XBox 360上针对.NET Compact、Windows Phone 7或八年前的Silverlight吗?如果是这样,你可能无法避免PCL,但我们大多数人都有幸能够避免它。如果不行:如果你的配置文件与.NET Standard中的任何内容都不匹配,请排队等待单独的PCL构建。

如果你的库非常简单(不使用反射、不使用async/await,不依赖于像WCF这样的大型框架),那么你可能能够针对.NET 2.0和具有所需框架依赖关系的最低版本的.NET Standard。不要被愚弄,较低版本的.NET Standard在提供的功能方面真的令人失望,但是你必须为可移植性付出一些代价。没有工具链支持同时构建.NET 2.0和某个.NET Standard版本。你必须构建两次并在“每个地方”进行测试,尽管交叉部分意味着如果编译通过,你可以相当肯定它会正常工作。生成的库将支持几乎所有可以加载纯.NET 2.0程序集的.NET平台(几乎所有平台,但特别不包括Micro和Compact)和.NET Core,而且无需平台切换。恭喜,世界上从未见过如此便携的东西!
如果你的库使用了反射,那么你可能无法避免重写代码以使其能够在.NET Core中编译,因为反射API已经改变,而你的代码可能还没有跟上(因为你一直只针对完整框架)。在这种情况下,你需要将目标.NET Framework版本提升到4.5,因为这是与这些更改兼容的.NET Framework版本。在这里你开始得到工具支持:你可以针对.NET Standard 1.1,它覆盖了.NET 4.5的子集。如果你发现这个子集不够用,你就必须再次构建两次:一次是针对完整的.NET Framework,另一次是针对.NET Core。原因是.NET Core 1.0支持比.NET Framework 4.5更多的内容,但是目前还没有与Core相媲美的.NET Framework版本(那将是“vNext”)。因此,如果你不想仅限于.NET Core,而且还想支持我们仍在构建纯粹的4.5桌面应用程序,而.NET Standard 1.1对你来说不够用,那么你就必须进行拆分。错误的做法是针对1.1,并导入仅支持Framework 4.5的包/程序集,因为这将在可移植性方面带来两个世界中最糟糕的结果!
如果您的库需要一些在4.5.1或更高版本中引入的改进/扩展,或者只有在更高的.NET Standard版本中才可用的包,则应选择相应的更高.NET Standard版本。请注意,Microsoft 不再官方支持任何低于4.5.2的4.x版本。这并不意味着您不应该针对那些版本(尽可能低),但这确实意味着您有理由使用不低于.NET Standard 1.2,如果您可以要求4.6,则不低于1.5。这对消费者来说并不繁琐(如果您愿意且能够安装4.6,则几乎肯定愿意且能够安装4.6.2),并使您的生活更轻松。根据您的代码,您可以仅使用.NET Core构建,但您可能不想这样做,因为.NET Core构建链尚不稳定,并将返回到MSBuild(如前所述)。没有必要放弃所有项目文件以仅使用JSON,以后再次移回!

你的库是否使用了任何条件编译?请注意,在.NET Core工具链中,你会得到不同的预定义符号。它们非常烦人,因为它们坚持(比如)区分4.5、4.5.1和4.5.2之间的差异,如果你想覆盖“4.5及以上”的话,这是一件很麻烦的事情。虽然仔细的构建可以解决这个问题,但你仍然需要考虑这个问题。

我没有涉及移动构建(Xamarin和旧版Phone)的内容,因为我对此知之甚少!我想,构建方法与同时构建.NET Core和.NET Framework的方法大致相同,即只有在简单的库和不需要考虑向后兼容性的库中才能够进行一次构建,否则需要(至少)两次构建。但正如我在一开始所说的,欢迎您提出更正意见。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接