CLR via C# 1.1 将源代码编译为托管模块
CLR顾名思义,是指可被各种不同编程语言使用的运行时。CLR的核心特性可用于所有面向它的编程语言。例如,运行时使用异常来报告错误,那么所有面向运行时的语言都可以通过异常来得到错误报告。又如,运行时也允许创建线程,因此所有面向运行时的语言也都可以创建线程。
在运行时,CLR对开发人员使用什么语言来完成源代码一无所知。我们可以选择任意语言来编写代码,只要其编译器可以编译面向CLR的代码。
如何选择语言呢?作者认为编译器是语法检查器和“正确代码”的分析器,它检查源代码,确保你编写的有意义,并输出描述你意图的代码。不同的语言拥有不同的语法。针对不同的目的,可以选择不同的语言。可以使代码量大幅缩减。
微软目前创建的面向CLR的语言编译器有:C++/CLI、C#、Visual Basic、F#、IronPython、IronRuby和一个中间语言汇编器(Intermediate Language Assembler)。
托管模块
下图显示了编译源代码文件的过程。如图所示,我们可以使用任何支持CLR的语言来编写源代码文件,然后相应的编译器将检查语法,并分析源代码。不管使用何种编译器,最终的结果都是托管模块(Managed Module)。托管模块是一个需要CLR才能够执行的标准的32位Microsoft Windows可移植可执行(PE32)文件,或标准的64位Windows可移植可执行(PE32+)文件。
托管模块的组成
大多数早期编译器产生的代码都是面向特定CPU架构的。而所有CLR兼容的编译器所生成的都是IL代码。IL代码也被称为托管代码(managed code),因为CLR管理其执行。
元数据
除了生成IL,每个面向CLR的编译器还为需要所有托管模块生成完整的元数据。简而言之,元数据是一个数据表的集合,这些数据表有一些描述托管模块所定义的内容(如定义的类型和它们的成员),此外还有一些描述托管模块所引用的内容(如引用的类型和它们的成员)。元数据是一些早期技术如COM类型库和IDL(接口定义语言)文件的超集。需要指出的是,CLR的元数据远比它们要完整。并且与类型库和IDL不同的是,元数据总是与包含IL代码的文件相关联。事实上元数据总是和这些代码(IL代码?)一起嵌入于同一个EXE/DLL文件中,两者不可分离。由于编译器同时产生元数据和IL代码,并将它们绑定到生成的托管模块之中,因此元数据及其所描述的IL代码之间总能保持同步。
元数据的用途
有关元数据更详细的内容,在第2章。
C#、VB.NET、F#和IL编译器总是产生包含托管代码(IL)和托管数据(GC数据类型)的模块。最终用户要执行这些包含托管代码和托管数据的模块,就必须安装CLR(目前作为.NET Framework的一部分发布)。这和要运行MFC或VB6应用一定要安装MFC库和VB DLLs是同样的道理。
默认情况下,C++编译器生成的是包含非托管(本地)代码的EXE/DLL模块,在运行时操作的是非托管数据(本地内存)。执行这些模块不需要CLR。然而,如果指定/CLR命令行选项,C++编译器将生成包含托管代码的模块,并且执行环境也必须安装CLR。C++是唯一允许开发者编写托管和非托管代码并将其生成到同一个模块中的编译器。这使得开发者可以在非托管代码中使用托管代码。
CLR via C# 1.1 将源代码编译为托管模块