读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

2.1 历史的枷锁

1、windows下的.net

CLR(通用预言运行时)本质上就是.NET虚拟机,作为一个运行时,CLR为程序的执行提供一个托管的执行环境。

程序集:程序集时.NET最基本的部署单元,无论定义中的多少类型被使用,CLR总是将整个程序集加载到内存中。

2、非windows下的.NET

.NET通过mono和Xamarin已经延申到了macOS、Linux、ios、Android。具备跨平台的能力。

.NET跨平台的能力建立在一种开放的标准或者规范【CLI】之上。

CLI(Common Language Infrastructure) 需要解决 编程语言的差异和运行时环境的差异。

要实现真正的跨平台,要解决可执行代码在不同平台之间的兼容和可移植问题

编程语言的选择仅仅决定了应用程序源文件的原始状态,应用的兼容性和可移植性由编译后的结果决定。若一个编译器能将不同语言的代码编译成相同的目标代码,那么语言差异性不再是个问题。

  • 编程语言的差异性通过编译器得以“同一化”
  • 运行时的差异性通过VM虚拟机技术(运行时)来解决

2.2 复用之伤

从源代码复用 ->程序集复用 ->可移植类库(PCL)

.NET从诞生那一刻就具有跨平台的“基因”,由于采用了统一的中间语言,微软只需要针对不同的平台设计不同的虚拟机(运行时)就能弥合不同操作系统与处理器架构之间的差异,但是“理想很丰满,现实很骨感”。在过去十多年中,微软将.NET引入到了各个不同的应用领域,但是由于采用完全独立的多目标框架的设计思路,导致针对多目标框架的代码平台只能通过PCL这种“妥协”的方式来解决。

2.3 全新的布局

.NETCore

要真正实现.NET 的跨平台伟业,主要需要解决两个问题,一是针对不同的平台设计相应的运行时为中间语言CIL提供一个一致性的执行环境,二是提供统一的BCL以彻底解决代码复用的难题。

对于真正跨平台的.NET Core来说,微软不仅为它设计了针对不同平台被成为CoreCLR的运行时,同时还重新设计了一套被称为CoreFX的BCL【Base class Library】。

作为运行时的CoreCLR和提供BCL的CoreFX是.NET Core两根重要的基石

1、CoreFX

我们知道对于传统的.NET Framework来说,承载BCL的API几乎都定义在mscorlib.dll这个程序集中,这些API并不是全部都转移到组成CoreFX的众多程序集中,

那些与运行时(CoreCLR)具有紧密关系的底层API被定义到一个叫做System.Private.CoreLib.dll的程序集中,所以下图反映了真正的.NET Core层次结构。

我们在编程过程中使用的基础数据类型基本上都定义在这个程序集中,所以目前这个程序集的尺寸已经超过了10M。由于该程序集提供的API与运行时关联较为紧密,较之CoreFX提供的API,这些基础API具有较高的稳定性,所以它是随着CoreCLR一起发布的。

【.net core框架下 程序集主要主要是: CoreFX和System.Private.CoreLib.dll这个核心程序集】

读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

虽然我们编程过程中使用到的绝大部分基础类型都定义在System.Private.CoreLib.dll程序集中,但是这却是一个“私有”的程序集,并不是说定义其中的都是一些私有类型,而是因为我们在编程的过程不会真正引用这个程序集,这与.NET Framework下的mscorlib.dll是不一样的。不仅如此,当我们编写的.NET Core代码被编译的时候,编译器也不会链接到这个程序集上,也就是说编译后生成的程序集中同样也没有针对该程序集引用的元数据。但是当我们的应用被真正执行的时候,所有引用的基础类型全部会自动 “转移” 到这个程序集中

Type Forwarding技术

利用反编译工具:ildasm.exe 【C:Program Files (x86)Microsoft SDKsWindowsv10.0Ain】

读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

 利用Type Forwarding方式实现跨程序集类型转移的技术成为“垫片(Shim)”,这是实现程序集跨平台复用的重要手段。

2、统一的BCL

读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

 被微软重新布局的.NET平台只包含了以上三个分支,但是之前遇到的一个重要的问题依然存在,那就是代码的复用【确切的说应该是 程序集的复用】。我们知道之前解决程序集复用的方案是PCL,但这并不是一种理想的解决方案,由于各个目标框架具有各种独立的BCL,所以我们创建的PCL项目只能建立在指定的几种兼容目标框架的BCL交集之上。

对于全新的.NET平台来说,这个问题通过提供统一的BCL得到根本的解决,这个统一的BCL被称为.NET Standard

如下图所示,.NET Standard为.NET Framework、.NET Core和Xamarin提供了统一的API,那么我们在这组标准API基础上编写的代码自然就能被所有类型的.NET应用复用。

读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

顾名思义,.NET Standard仅仅是一个标准,而不提供具体的实现。我们可以简单理解为.NET Standard为我们定义了一整套标准的接口,各个分支需要针对自身的执行环境对这套接口提供实现。

对于.NET Core来说,它的基础API主要由CoreFX和System.Private.CoreLib.dll这个核心程序集来承载,这些API基本上就是根据.NET Standard来设计的

但是对.NET Framework来说,它的BCL提供的API与.NET Standard存在着很大的交集,实际上.NET Standard基本上就是根据.NET Framework现有的API来设计的,所以微软不可能在.NET Framework上重写一套类型于CoreFX的实现,只需要采用某个技术 “链接” 到现有的程序集上就可以了。

  • 其中:一个核心的程序集netstandard.dll,.NET Standard API就定义在该程序集中
  • 所有.NET Standard 项目都具有针对程序集netstandard.dll的依赖,这个依赖自然也会体现在编译后生成的程序集上

示例【略】

针对Dictionary<,>和SortedDictionary<,>这两个类型分别在.NET Framework 4.7和.NET Core环境下的跨程序集转移路径基本上体现在下图之中。简单来说,

不同分支框架下的程序,调用.NET Standard类型的类库,其链接技术如下:

.NET Framework环境下的垫片程序集netstandard.dll将这两个类型分别转移到了程序集mscorlib.dll和System.dll之中

如果执行环境切换到了.NET Core,这两个类型先被转移到System.Collection.dll中,但是Dictionary<,>这个常用类型最终是由System.Private.CoreLib.dll这个基础程序集承载的,所有System.Collection.dll中针对该类型作了二次转移。

读《ASP.NET Core3框架揭秘》之2~跨平台的奥秘

.NET Standard为什么能够提供全平台的可移植性,.NET Standard API由NetStandard.Library这个NuGet包来承载,后者提供了一个名为netstandard.dll的程序集,保留在这个程序集中的仅仅是. NET Standard API的存根(Stub),而不提供具体的实现。

所有对于一个目标框架为.NET Standard的类库项目编译生成的程序集来说,它们保留了针对程序集netstandard.dll的引用。

.NET平台的三大分支(.NET Framework、.NET Core和Xamarin)按照自己的方式各自实现了.NET Standard规定的这套标准的API。由于在运行时真正承载.NET Standard API的类型被分布到多个程序集中,所以. NET Standard程序集能够被复用的前提是运行时能够将这些基础类型链接到对应的程序集上。由于. NET Standard程序集是针对netstandard.dll进行编译的,所以我们只需要在各自环境中提供这个同名的程序集来完成类型的转移【程序集内部自定义了转移】即可。

更多参考:https://www.cnblogs.com/artech/p/how-to-cross-platform-01.html