可以这样理解:.NET Standard是.NET跨平台的根本。.NET Standard其实就是一套.NET下的API规范,它的第一个版本与2016年的.NET Core 1.0同时发布,每一个版本的.NET Standard都规定了实现这一版本规范的差别的.NET实现应该包含哪些API。更具体些:为了跨Linux、MacOS、Windows、iOS、Android等多个平台,.NET会针对这些平台提供差别的实现,这些实现包括:.NET Core、.NET Framework、Xamarin套件(iOS、Mac和Andriod)、用于游戏开发的Unity下的.NET等等,假如这些实现可以或许遵照某个版本的API标准,那么,基于这个版本的API标准所开发的应用程序,就可以运行于这些差别平台上,而这套API标准就是.NET Standard。另一方面,假如希望开发出来的类库和组件可以或许被差别平台的应用程序使用,那么,只需要指定这个类库和组件所基于的.NET Standard版本即可。
然而,最开始的.NET Framework并不能跨平台,微软为了逐步实现.NET跨平台这个目标,先后发布了从1.0到2.1一共9个版本的.NET Standard,每个.NET Standard版本下,都增加一部分.NET API的支持,比如,.NET Standard 1.0仅支持37118个API中的7949个,.NET Standard 2.0支持37118个API中的32638个,而最新的.NET Standard 2.1则支持所有37118个API。因此,在差别版本的.NET Standard下,就会有对应版本的.NET实现对其进行支持。比如对于.NET Standard 2.0,经典的.NET Framework需要4.6.1及以上的版本才支持.NET Standard 2.0,由于这些版本实现了.NET Standard 2.0中所定义的那32638个API。于是,使用.NET Standard 2.0开发的类库,就可以被.NET Framework 4.6.1所引用。
演练:在差别的.NET项目中使用.NET Standard 2.0类库
在Visual Studio 2022中,新建一个.NET Standard 2.0的Class Library:
但是,假如我们新建一个.NET Standard 2.1的Class Library,则无法被.NET Framework 4.6.1的项目引用,此时会报错:
由于.NET Framework 4.6.1没有实现.NET Standard 2.1,换句话说,.NET Standard 2.1中的有些API在.NET Framework 4.6.1中并没有实现,那么基于.NET Standard 2.1开发出来的类库天然也不能被.NET Framework 4.6.1的项目所引用。经典.NET Framework的末了一个版本4.8.1仅实现了.NET Standard 2.0,因此,假如你计划开发一个既可以被经典.NET Framework项目使用,又可以被跨平台.NET(曾经的.NET Core,现在的.NET 5+)项目使用的话,你需要将你的类库定向(targeting)到.NET Standard 2.0,或者使用多目标框架(Multi-targeting)。
在【这个页面】中,有一张表,展示了.NET Standard各个版本与差别的.NET实现的版本之间的对应关系,可以通过下拉框来选择差别的.NET Standard版原来检察差别的.NET实现的哪些版本与之对应。理论如此,但是在真正实践的过程中,有些具体的题目是需要特殊处置惩罚的。比如:.NET Framework 4.7是支持.NET Standard 2.0的,但是,.NET Framework 4.7发布于2017年4月,而.NET Standard 2.0则晚于.NET Framework 4.7发布(2017年8月),那么如何让一个已经发布的.NET Framework版本支持新的.NET Standard呢?解决方案就是使用NuGet Package,将.NET Framework中未实现的.NET Standard API以NuGet Package的形式引入,从而弥补这个差异。因此你会发现,对于.NET Framework 4.7.1及其以前版本的.NET项目,假如需要引用一个由.NET Standard 2.0实现的类库的话,就需要额外引用NETStandard.Library这个Meta Package,这个Meta Package中包含了差别版本.NET项目所需依靠的Assembly的版本信息。另外,Visual Studio在处置惩罚这个事情上也有差异:
Visual Studio 2017 15.3之前的版本需要在IDE中显式引用这个Meta Package
从Visual Studio 2017 15.3开始,不再需要在IDE中显式引用这个Meta Package,也就是说,在新建的.NET Framework 4.7.1及以前版本的项目上引用.NET Standard 2.0,不再需要额外去引用NETStandard.Library,Visual Studio会主动帮你完成这个工作。当然,这并不表现你的项目就不需要NETStandard.Library了,只是在IDE的操作上比以前更加简朴了
在编译出来的效果上也存在差异,下面左图是一个.NET Framework 4.7的项目引用了一个.NET Standard 2.0的项目后的编译输出,右图是.NET Framework 4.8.1的项目引用了.NET Standard 2.0项目后的编译输出,可以看到,4.7的项目编译后,会在编译路径下天生一堆System DLL,外加一个netstandard.dll,而4.8.1的项目编译天生路径下就非常干净,由于.NET Framework 4.8.1已经自带了这些DLL了:
多目标框架(Multi-targeting)
尽管.NET Standard提供了差别.NET实现(.NET Framework、.NET Core和Xamarin等)之间统一的API规范,但在有些场景下,仍然希望可以或许充分使用差别平台的特性和性能优化,或者需要支持特定平台的功能,此时仅将项目定向到.NET Standard已经不能满足需求。对于这种场景,.NET允许开发面向多目标框架的类库,一方面可以通过条件编译指令来使用特定平台的API,另一方面也可以为类库的调用方提供差别平台的支持。
比如,在C#项目文件(.csproj文件)中,使用下面的方式,让类库同时支持.NET Standard 2.1项目和.NET Framework 4.8的项目:
那么,是不是所有的C# 9.0的新特性,都可以在.NET Framework 4.6.1中使用呢?答案是否定的,就要看C# 9.0的编译器是否可以天生可以或许被该版本.NET Framework所支持的代码,或者说,C#编译器所天生的代码中依靠的那些类型,是否在该版本的.NET Framework下支持。举个例子,同样是C# 9.0的新特性,仅限Init的资源库新特性则无法直接在一个.NET Framework 4.6.1的项目中使用,编译器提示:Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported: