执行C#程序的运行时由公共语言运行时(Common Language Runtime)和基础类库构成。运行时还可以包含更高层次的应用程序层,其中包含用于开发富客户端、移动或Web应用程序(参见图1-1)的类库。不同的运行时可以在不同的平台开发多种类型的应用程序。
图1-1:运行时架构
公共语言运行时(Common Language Runtime,CLR)提供必需的运行时服务,例如,自动化内存管理与异常处理。其中“公共”指其他托管编程语言(如F#、Visual Basic和托管C++),也能共享该运行时。
C#是一种托管语言,因为它也会将源代码编译为托管代码,托管代码以中间语言(Intermediate Language,IL)的形式表示。CLR通常会在执行前将IL转换为机器(例如X64或X86)原生代码,该技术称为即时(Just-In-Time,JIT)编译。除此之外,还可以使用提前编译(ahead-of-time compilation)的方式改善那些拥有大量程序集,或需要在资源有限的设备上运行的程序的启动速度(以确保开发的移动端应用程序能够达到iOS应用商店标准。)
托管代码的容器称为程序集(assembly)。它们不仅包含IL,还包含类型信息(元数据)。元数据的引入使程序集无须额外的文件就可以引用其他程序集中的类型。
Microsoft的ildasm工具可以反编译程序集或查看程序集的内容。其他工具(例如ILSpy与JetBrains的dotPeek)则可以将IL代码进一步反编译为C#。IL的层次相比原生机器代码要高得多,因此反编译器可以高质量地重建C#代码。
程序也可以通过反射(reflection)查询其中的元数据,甚至在运行时生成新的IL( reflection.emit )。
CLR总是与一组程序集一同发行。这组程序集称为基础类库(Base Class Library,BCL)。BCL向程序员提供了最核心的编程能力。例如,集合、输入/输出、文本处理、XML/JSON处理、网络编程、加密、互操作、并发和并行编程。
BCL还实现了C#语言本身所需的类型(为了支持枚举、查询和异步等功能),并可以让你显式访问CLR功能,例如反射与内存管理。
运行时(或称为框架)是一个可下载并安装的部署单元。运行时包含CLR(以及BCL),还可以包含开发特定应用程序(例如Web、移动应用、富客户端应用程序等)所需的应用程序层。若只是开发命令行控制台应用程序或非UI类库,则无须应用程序层。
在开发应用程序时,需要选定一个特定的目标运行时,即应用程序依赖该运行时提供的功能。运行时的选择也决定了应用程序支持的平台。
下表列出了主流的运行时选项:
图1-2使用图形的方式展示了上述内容,并展示了本书涵盖的内容。
图1-2:C#的运行时
.NET 6是Microsoft的旗舰级开源运行时。它可以在Windows、Linux和macOS上运行.NET Web与命令行应用程序,也可以在Windows 7~11、macOS与在iOS和Android移动应用程序上运行.NET富客户端应用程序。本书将关注.NET 6 CLR与BCL。
和.NET Framework不同,.NET 6并未随Windows预先安装在机器上。在运行.NET 6应用程序时,若无法找到正确的运行时则会出现提示信息,并指引你访问运行时下载页面。你可以使用自包含部署方式(self-contained deployment)避免上述情况。这种部署方式会将应用程序所需的部分运行时包含在程序中。
.NET 6是.NET 5的更新版本,而更早的版本是.NET Core 3。Microsoft去掉了“Core”并跳过了4这个版本号,以避免和.NET Framework 4.x混淆。
因此,使用.NET Core 1、2和3或.NET 5编译的程序集在绝大多数情况下不加修改就可以在.NET 6上运行。相反,使用(任何版本的).NET Framework编译的程序集通常和.NET 6是不兼容的。
.NET 6的BCL和CLR与.NET 5(和.NET Core 3)非常相似,它们的不同之处主要体现在性能和部署方式上。
MAUI(Multiple-platform App UI,多平台应用程序UI,于2022年初发布)用于设计支持iOS和Android的移动应用程序,以及支持macOS和Windows的跨平台桌面应用程序。MAUI由Xamarin进化而来,允许单一项目支持多种平台。
UWP(Universal Windows Platform)用于编写沉浸式触控优先的应用程序。这些应用程序可以运行在Windows 10+桌面系统以及Xbox、Surface Hub和Hololens等设备上。UWP应用运行在沙盒之内,并可通过Windows Store发行。Windows 10操作系统中预装了UWP。UWP基于.NET Core 2.2 CLR/BCL,目前看来这种依存关系会持续下去。其后继者WinUI 3 则作为Windows App SDK的组成部分随之发布。
Windows App SDK支持.NET的最新版本,它和.NET Desktop API集成度更佳,并且可以脱离沙盒执行。但是它目前并不支持XBox或HoloLens等设备。
.NET Framework是Microsoft最初的Windows独占运行时,用于编写(只)运行于Windows桌面系统和服务器系统的网络应用程序与富客户端应用程序。虽然Microsoft会继续支持和维护当前的4.8版本以保证现有应用程序的执行,但该框架目前已没有后续的发布计划。
.NET Framework中的CLR和BCL与应用层集成在一起。使用.NET Framework编写的应用程序通常在进行少许修改后就可以在.NET 6中重新编译。.NET Framework中含有一些.NET 6并不具备的特性,反之亦然。
Windows预装了.NET Framework,会通过Windows升级服务自动升级。若将目标框架设置为.NET Framework 4.8,则可以使用C# 7.3及之前版本的语言功能。
.NET这个词之前一直用以指代任何与.NET相关的技术(例如.NET Framework、.NET Core、.NET Standard等)。
而微软将.NET Core重新命名为.NET不可避免会造成误解。在本书中,我们使用.NET表示.NET 5+,而使用“.NET Core和.NET 5+”指代.NET Core及其后续版本。
更令人费解的是.NET 5(+)本身也是一个框架(framework),但它和之前的.NET Framework截然不同。因此我们尽可能使用“运行时”这个术语而不用“框架”这个词。
除了上述提到的运行时外,还有以下小众运行时:
· .NET Micro Framework是在资源非常受限的嵌入式设备上运行.NET代码的框架(大小在1MB以内)。
· Unity是一个游戏开发平台。它使用C#作为脚本语言进行游戏逻辑的开发。
除此之外,我们还可以在SQL Server上执行托管代码。SQL Server的CLR集成环境支持在SQL中调用C#开发的自定义函数、存储过程以及聚合函数。它虽然使用.NET Framework,但是其中的沙盒是由特殊的CLR宿主提供的,以保护SQL Server进程无恙。