第一章: Microsoft .net 框架开发平台体系架构
本章的目标:对 .net 框架体系架构有一个总体的认识,并对 .net 框架中出现的一些新的技术和术语有一个基本的了解。
1.1 将源代码编译为托管模块
** ** ** 关于编程语言的选择 **
.net 框架的核心是通用语言运行时,顾名思义它是一个可被各种不同的编程语言所使用的运行时。 CLR 的很多特性可用于所有面向它的编程语言,如果 CLR 用异常来报告错误,那么所有面向它的语言都将通过异常来得到错误报告。如果 CLR 允许我们创建线程,那么所有面向它的语言也都可以创建线程。
实际上 CLR 在运行时对开发人员用何种编程语言来完成源代码一无所知。这意味着我们应该选择那些能够最容易表达我们意图的编程语言。我们可以用任何自己喜欢的语言(面向 CLR 的)来编写代码。
不同的编程语言允许我们使用不同的语法进行开发,不同的语法对于我们解决各种问题的难易程度是有影响的,例如:对于数学或者金融应用,彩用 APL 语法更快。
微软已经创建了以下几种面向 CLR 的编译器 :
托管扩展 C++
C#
Visual Basic
Jscript
J#
IL 汇编器
我们可以用任何支持 CLR 的编程语言来创建源代码文件。然后用相应的编译器来做语法检查和源代码分析。最后生成托管橡块。
** 托管模块 **
** ** ** 托管模块是一个需要 CLR ** ** 才能执行的标准 Windows ** ** 可移植可执行 (Portable executable, ** ** 简称 PE) ** ** 文件。 **
** 托管模块 ** 的组成部分:
l PE 表头
标准 Windows PE 文件表头,类似于通用对像文件格式表头。该表头指出了文件的类型: GUI( 图形用户界面 ) , CUI( 控制台用户界面 ) ,或者 DLL. 此处的 DLl 并非我们理解的传统的 windows 动态链接库文件,虽然都叫 DLL ,但 ,net 平台中的 DLL 指程序集文件的一种形式),该表头还包含文件创建时间。对于包含 CPU 代码的模块,该表头还会包含有关本地 CPU 代码的一些信息
l CLR 表头
包含标识托管模块的一些信息(可以被 CLR 或者一些实用工具解析)。
1、 CLR 版本号
2、 托管模块入口点方法( Main 方法)的元数据标记
3、 托管模块的元数据标记
4、 资源
5、 强命名
6、 其他一些意义不是太大的信息的位置和尺寸
l 元数据
每个托管模块都包含有一些元数据表。元数据表主要分两种,一种用于描述源代码中定义的类型和成员,一种用于描述源代码中的引用类型和成员。
l 中间语言( IL )和代码
编译器在编译源代码是产生的指令。 CLR 在运行时会将 IL 代码编译成本地 CPU 指令
** 元数据( metadata ** ** ) ** 就是一个数据表的集合,在这些表中,其中一些用于描述托管模块中所定义的内容(比如所定义的类型和它们的成员,另外一些用于描述托管模块中引用的内容(比如被引用的类型和它们的成员)。元数据总是和包含 IL 代码的的文件相关联。
** 元数据的用处: **
1、 省去了源代码编译时对头文件和库文件的需求,
2、 Visual Studio .Net 可以利用元数据来辅助我们编写代码。智能感知就是这样做的。
3、 可以序列化和反序列化
4、 垃圾收集器可以追踪对像的生存期。
1.2 将托管模块组合为程序集
CLR 实际上并不和托管模块打交道,它直接打交道的对象是 程序集 ( assembly ) . 程序集是一个抽象的概念,刚开始往往很难理解。首先,程序集是一个或多个托管模块,以及一些资源文件的逻辑组合。其次,程序集是组件复用,以及实施安全策略和版本的最小单位。根据我们对编译器和相关工具所做的选择,程序集可以是一个文件或者多个文件。
默认情况下,编译器会将产生的托管模块转换为一个程序集。也就是说, c# 编译器产生的是一个我包含了清单的托管模。其中的清单表明程序集中仅包含一个文件。对于仅包含一个托管模块,并且没有资源(或者数据)文件的项目来说,程序集就是托管模块,而且在创建过程中,不需要执行任何其他的步骤。
程序集中的模块还包含它所引用的程序集的一些信息(如版本号信息)。这些信息使得一个程序集得以实现自描述( self-describing )。换句话说, CLR 知道执行一个程序集所需要的所有内容,它不需要再在注册表或者活动目录中获取额外的信息。因此,程序集的部署要比非托管组件的部署容易得多。
1.3加载通用语言运行时
一个程序集或者是一个可执行应用程序,或者是一个包含供可执行应用程序使用的一组类型(组件)的 DLL 。 CLR 负责管理包含在程序集中的代码的执行。这意味着宿主机器必须安装 .net 框架。微软已经创建了一个可以将 .net 框架免费安装到客户机上的分发包。 .net 框架最终会和将来的 Windows 打包在一起,这样我们就不需要将它和我们的程序集放在一起来发布了。
我们可以通过在 %windir%\system32 目录下查找 MSCorEE.dll 文件来判断一个机器中是 否安装了 .NET 框架。如果想确定一个机器中安装了哪些版本的 .NET 框架,可以查看下面的注册表键的子键:
HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ .NETFramework \ policy
当生成一个 EXE 程序集时,编译器/链接器会产生一些特殊的信息,并将它们嵌入到结果程序集的 PE 文件表头及其各个组成文件的 .text 部分。当 EXE 文件被调用时,这些特殊的信息将导致 CLR 被加载并初始化。 CLR 随后会定位至应胜程序的入口点方法,从面以此来启动应用程序。
类似地,如果是一个非托管应用程序通过调用 LoadLibrary 来加载一个托管程序集,那么该托管程序集 DLL 的入口点函数也会知道去加载 CLR 来处理包含在其中的代码。
** 托管 ** ** EXE ** ** 加载并初始化 ** ** CLR ** ** 的过程 ** ** **
1. MSCorEE 检查 CLR 表头以获得 Main 方法的元数据标记。
2. MSCorEE 检查 Main 方法的元数据以获得其 IL 在托管 EXE 中的位置。
3. MSCorEE 将 Main 方法的 IL 编译成本地 CPU 指令。
4. MSCorEE 跳转到 Main 方法编译后的本地 CPU 指令上(使用主线程)
5. 应用程序开始运行。
托管 DLL 的情形与此类似。