2.2.2可操控执行的含义 前面的叙述中,我们多次提到了“可操控”这一概念。这意味着它指向的对象在 执行过程中完全被运行时环境所控制。在执行过程中,运行时环境提供以下服务:自 动内存管理、调试支持、增强的安全性及与非可操控代码的互操作性,例如COM组件。 在可控执行进程中的第一步是选择源代码的生成工具。如果你希望你的应用拥有 CLR提供的优势,你必须使用一种(或多种)以运行时为目标的语言编译器,例如: VB、C#、ⅤC的编译器,或者一种第三方编译器如PERL或 COBOL编译器 由于运行时是一种多语言执行环境,它支持众多的数据类型和语言特性。你使用 的语言编译器决定你将使用运行时的哪一部分功能子集。在代码中使用的语法由你的 编译器决定,而不是运行时环境。如果你的组件需要被其他语言的组件完全使用,那 么你必须在你组件的输出类型中使用CLR所要求的语言特征。 当你完成并编译你的代码时,编译器将它转换为微软中间语言( Microsoft Intermediate Language,MS),同时产生元数据。当你要执行你的代码时,这种中间 语言被即时( Just in time,JI)编译器编译成为本地代码。如果安全策略需要的代码 是类型安全的——通常情况下都是如此——J编译器将在编译进程中对中间语言进行 类型检査。一旦失败,在代码执行中将会触发异常。 223CLR的突出特色 跨语言集成的能力 CLR包含了一个丰富的语言特性集,保证了它与各种程序设计语言的兼容性。这 特性集即公用语言规范,稍后将对其进行详细说明。 内存管理自动化 在执行过程中管理应用程序的资源是一项单调而困难的工作。它会将你的注意力 从你本应解决的问题中引开。而垃圾收集机制完全解决了程序员在编程过程中头痛的 问题,跟踪内存的使用,并知道何时将它们释放。 在面向对象的环境中,每种类型都标识了对你的应用有用的某种资源。为了使用 这些资源,你需要为类型分配内存。在应用中,访问一种资源要通过以下步骤 (1)为类型分配内存 (2)初始化内存,设置资源的初始状态并使其可用。 (3)通过访问该类型的实例成员来访问资源 (4)卸下将被清除的资源状态 (5)释放内存 这一看似简单的过程在实际的编程中是产生程序错误的主要来源之一。更可怕的 是:内存中的错误往往导致不可预见的结果。如果你有过编程的经验,想想看,有多 少次你的程序因为内存访问错误而崩溃? CLR要求所有的资源从可操控的堆(注:在此指一种内存结构)中分配。当一个
2.2.2 可操控执行的含义 前面的叙述中 我们多次提到了 可操控 这一概念 这意味着它指向的对象在 执行过程中完全被运行时环境所控制 在执行过程中 运行时环境提供以下服务 自 动内存管理 调试支持 增强的安全性及与非可操控代码的互操作性 例如 COM 组件 在可控执行进程中的第一步是选择源代码的生成工具 如果你希望你的应用拥有 CLR 提供的优势 你必须使用一种 或多种 以运行时为目标的语言编译器 例如 VB C# VC 的编译器 或者一种第三方编译器如 PERL 或 COBOL 编译器 由于运行时是一种多语言执行环境 它支持众多的数据类型和语言特性 你使用 的语言编译器决定你将使用运行时的哪一部分功能子集 在代码中使用的语法由你的 编译器决定 而不是运行时环境 如果你的组件需要被其他语言的组件完全使用 那 么你必须在你组件的输出类型中使用 CLR 所要求的语言特征 当你完成并编译你的代码时 编译器将它转换为微软中间语言 Microsoft Intermediate Language MSIL 同时产生元数据 当你要执行你的代码时 这种中间 语言被即时 Just In Time JIT 编译器编译成为本地代码 如果安全策略需要的代码 是类型安全的 通常情况下都是如此 JIT 编译器将在编译进程中对中间语言进行 类型检查 一旦失败 在代码执行中将会触发异常 2.2.3 CLR 的突出特色 跨语言集成的能力 CLR 包含了一个丰富的语言特性集 保证了它与各种程序设计语言的兼容性 这 一特性集即公用语言规范 稍后将对其进行详细说明 内存管理自动化 在执行过程中管理应用程序的资源是一项单调而困难的工作 它会将你的注意力 从你本应解决的问题中引开 而垃圾收集机制完全解决了程序员在编程过程中头痛的 问题 跟踪内存的使用 并知道何时将它们释放 在面向对象的环境中 每种类型都标识了对你的应用有用的某种资源 为了使用 这些资源 你需要为类型分配内存 在应用中 访问一种资源要通过以下步骤 1 为类型分配内存 2 初始化内存 设置资源的初始状态并使其可用 3 通过访问该类型的实例成员来访问资源 4 卸下将被清除的资源状态 5 释放内存 这一看似简单的过程在实际的编程中是产生程序错误的主要来源之一 更可怕的 是 内存中的错误往往导致不可预见的结果 如果你有过编程的经验 想想看 有多 少次你的程序因为内存访问错误而崩溃 CLR 要求所有的资源从可操控的堆 注 在此指一种内存结构 中分配 当一个
进程被初始化后,CLR保留了一个未被分配的地址空间。这一区域叫做可操控堆。在 堆中保持了指向下一个将被分配给对象的堆地址的指针(NEXT)。初始状态下,该指 针是保留地址空间的基地址。一个应用使用新的操作产生对象。此操作首先检查新对 象需要字节的大小是否会超出保留空间。如果对象大小合适,指向下一个地址的指针 将指向堆中的这个对象,该对象的构造器被调用,新的操作返回对象的地址。 当一个应用请求建立一个对象时,地址空间可能不够大。堆将发现这一点(通过 将新对象的大小与NEXT指针相加,并与堆的大小进行比较),这时垃圾收集器就将被 调用。在这里,CLR引入了“代”的概念。代,指堆中对象产生的先后。这样,垃圾 收集器在将发生溢出时回收属于特定的“代”的对象,而不是回收堆中的所有对象 (6)即时编译。 在各种语言的编译器对源代码进行编译之后,在CLR环境中产生的是中间代码(出 于兼容性与跨语言集成的考虑),其内容虽然有效,但在转化为本地代码之前它本身是 不可执行的。这就是JT编译器需要完成的工作 这里需要说明一个问题:为什么要即时编译,而不是一次性的将中间代码文件进 行编译?答案很简单:原因在于效率。在大型的应用中,你很少会用到程序的全部功 能,这种边执行边编译的措施比一次性的完全编译效率更高 在 Windows平台中,CLR带有三个不同的JT编译器 (7)缺省的编译器—一主编译器,由它进行数据流分析并输出经过优化的本地代 码,所有的中间代码指令均可被它处理 (8) PREJIT,它建立在主JI编译器之上。其运行方式更像一个传统的编译器 每当一个NET组件被安装时它就运行 (9) ECONOJIT,在并不充分优化的前提下,它能够快速完成Ⅱ代码到本地码的 转换,编译速度与运行速度都很快。 为了配合编译器的工作,在 NET SDK的安装路径下的bin目录中有一个负责管理 JIT的应用程序: Gutman.exeo具体的使用参见联机帮助。 (10)解决版本与发布问题。 在当前以组件为基础的系统中,开发人员和用户对于软件版本和发布中存在的问 题已经十分熟悉了。当我们安装一个新的应用之后,我们很可能发现原本正常的某个 应用程序奇怪地停止了工作。绝大多数开发人员将时间花在了确保所有注册表入口的 一致性,以便激活COM类上。这就是所谓的“DLL地狱 NET平台通过使用集合来解决这一问题。在这里,“集合”是一个专有名词,指 类型与资源的发布单元,在很大程度上它等同于今天的DLL。正像NET用元数据描述 类型一样,它也用元数据描述包含类型的集合。通常说来,集合由四个部分组成:集 合的元数据(集合的内部清单)、元数据描述的类型、实现类型的中间语言代码和一组 资源。在一个集合中,以上四个部分并不是都必须存在,但是,集合中必须包含类型 或资源,这样集合才有意义 在NET中一个基本的设计方针是使用孤立的组件。一个孤立的集合的含义是指一 个集合只能被一个应用所访问。在一台机器上,它不被多个应用共享,也不会受其它 应用程序对系统的更改的影响。“孤立”赋予了开发人员在自己的程序中对代码的完全
进程被初始化后 CLR 保留了一个未被分配的地址空间 这一区域叫做可操控堆 在 堆中保持了指向下一个将被分配给对象的堆地址的指针 NEXT 初始状态下 该指 针是保留地址空间的基地址 一个应用使用新的操作产生对象 此操作首先检查新对 象需要字节的大小是否会超出保留空间 如果对象大小合适 指向下一个地址的指针 将指向堆中的这个对象 该对象的构造器被调用 新的操作返回对象的地址 当一个应用请求建立一个对象时 地址空间可能不够大 堆将发现这一点 通过 将新对象的大小与 NEXT 指针相加 并与堆的大小进行比较 这时垃圾收集器就将被 调用 在这里 CLR 引入了 代 的概念 代 指堆中对象产生的先后 这样 垃圾 收集器在将发生溢出时回收属于特定的 代 的对象 而不是回收堆中的所有对象 6 即时编译 在各种语言的编译器对源代码进行编译之后 在 CLR 环境中产生的是中间代码 出 于兼容性与跨语言集成的考虑 其内容虽然有效 但在转化为本地代码之前它本身是 不可执行的 这就是 JIT 编译器需要完成的工作 这里需要说明一个问题 为什么要即时编译 而不是一次性的将中间代码文件进 行编译 答案很简单 原因在于效率 在大型的应用中 你很少会用到程序的全部功 能 这种边执行边编译的措施比一次性的完全编译效率更高 在 Windows 平台中 CLR 带有三个不同的 JIT 编译器 7 缺省的编译器 主编译器 由它进行数据流分析并输出经过优化的本地代 码 所有的中间代码指令均可被它处理 8 PREJIT 它建立在主 JIT 编译器之上 其运行方式更像一个传统的编译器 每当一个.NET 组件被安装时它就运行 9 ECONOJIT 在并不充分优化的前提下 它能够快速完成 IL 代码到本地码的 转换 编译速度与运行速度都很快 为了配合编译器的工作 在.NET SDK 的安装路径下的/bin 目录中有一个负责管理 JIT 的应用程序 jitman.exe 具体的使用参见联机帮助 10 解决版本与发布问题 在当前以组件为基础的系统中 开发人员和用户对于软件版本和发布中存在的问 题已经十分熟悉了 当我们安装一个新的应用之后 我们很可能发现原本正常的某个 应用程序奇怪地停止了工作 绝大多数开发人员将时间花在了确保所有注册表入口的 一致性 以便激活 COM 类上 这就是所谓的 DLL 地狱 .NET 平台通过使用集合来解决这一问题 在这里 集合 是一个专有名词 指 类型与资源的发布单元 在很大程度上它等同于今天的 DLL 正像.NET 用元数据描述 类型一样 它也用元数据描述包含类型的集合 通常说来 集合由四个部分组成 集 合的元数据 集合的内部清单 元数据描述的类型 实现类型的中间语言代码和一组 资源 在一个集合中 以上四个部分并不是都必须存在 但是 集合中必须包含类型 或资源 这样集合才有意义 在.NET 中一个基本的设计方针是使用孤立的组件 一个孤立的集合的含义是指一 个集合只能被一个应用所访问 在一台机器上 它不被多个应用共享 也不会受其它 应用程序对系统的更改的影响 孤立 赋予了开发人员在自己的程序中对代码的完全
控制权。任何共享代码都需要被明确地标识。同时,NET框架也支持共享集合的概念。 个共享集合指在一台机器上被多个应用共享的集合。共享集合需要严格地命名规定。 有了NET,应用程序间的共享代码是明确定义的。共享集合需要一些额外的规则来避 免我们今天遇到的共享冲突问题。共享代码必须有一个全局唯一的名称,系统必须提 供名称保护,并在每当引用共享集合时,CLR将对版本信息进行检査,此外NET框架 允许应用或管理员在明确说明的版本政策下重写集合的版本信息。 2.24公用语言规范 使被不同语言的编译器所编译的对象能够相互理解的唯一方法,是所有在互操作 过程中涉及的数据类型和语言特性对所有的语言来说是公共的。为了这个目的,公用 运行时环境标识了一组语言特征的集合,称为公用语言规范(CLS)。如果你的组件在 应用程序接口( Application Program Interface)中仅使用CLS的特征语言(包括子类 那么该组件能够被任何支持CLS的语言所编译的组件访问。所有支持CLS并仅使用CLS 中的语言特征的组件被称为符合CLS的组件。 设计公用语言规范时遇到的一个最主要的挑战是选择适当的语言特性子集的大 小。它应具有完全的表达能力,又应足够小,使得所有的语言能够容纳它。由于CLS 是关于语言互用性的规范,它的规则仅应用于外部可见的条目中。CLS假设语言间的 互操作性仅在语言集合的边界发生交叉时才是重要的。也就是说,在单一的语言集中 对于编程技术的使用没有任何限制。CLS的规则仅作用于在定义它们的语言集合之外 仍然可见的项上。这样就大大缩小了CLS的范围,减轻了系统的负担 在CLS中是用 System CLSCompliant Attribute类来标识一个集合或者类是否是符合 CLS规范的:在 System CLSCompliant Attribute的构造器中有一个 Boolean型的返回值 代表了与之相关联的项是否符合CLS规范 2.3开发工具 NET为使用与开发人员提供了功能强大、种类丰富的管理与开发工具,同时它们 也是NET框架提供的服务,我们将它们列在下面,正是由于有了它们的支持NET才 变得如此强大 1. Visual studio. NET:是NET的核心开发工具,包括微软提供的各种开发语言 其中有Ⅴ isual c# 2. Assembly Generation Utility( (al.exe):用来建立集合的工具。它能够将资源文件 或MSLL格式的文件转换为带有内容清单的集合。 3. Windows Forms ActiveX Control Importer( aximp. exe):完成COM类库中类型定 义的转换,使 ActiveX控件能够在 Windows窗口控件上使用。 4. Code Access Security Policy Utility( (caspol.exe):在用户与机器水平上修改安全策
控制权 任何共享代码都需要被明确地标识 同时 .NET 框架也支持共享集合的概念 一个共享集合指在一台机器上被多个应用共享的集合 共享集合需要严格地命名规定 有了.NET 应用程序间的共享代码是明确定义的 共享集合需要一些额外的规则来避 免我们今天遇到的共享冲突问题 共享代码必须有一个全局唯一的名称 系统必须提 供名称保护 并在每当引用共享集合时 CLR 将对版本信息进行检查 此外.NET 框架 允许应用或管理员在明确说明的版本政策下重写集合的版本信息 2.2.4 公用语言规范 使被不同语言的编译器所编译的对象能够相互理解的唯一方法 是所有在互操作 过程中涉及的数据类型和语言特性对所有的语言来说是公共的 为了这个目的 公用 运行时环境标识了一组语言特征的集合 称为公用语言规范 CLS 如果你的组件在 应用程序接口 Application Program Interface 中仅使用 CLS 的特征语言 包括子类 那么该组件能够被任何支持CLS的语言所编译的组件访问 所有支持CLS并仅使用CLS 中的语言特征的组件被称为符合 CLS 的组件 设计公用语言规范时遇到的一个最主要的挑战是选择适当的语言特性子集的大 小 它应具有完全的表达能力 又应足够小 使得所有的语言能够容纳它 由于 CLS 是关于语言互用性的规范 它的规则仅应用于外部可见的条目中 CLS 假设语言间的 互操作性仅在语言集合的边界发生交叉时才是重要的 也就是说 在单一的语言集中 对于编程技术的使用没有任何限制 CLS 的规则仅作用于在定义它们的语言集合之外 仍然可见的项上 这样就大大缩小了 CLS 的范围 减轻了系统的负担 在 CLS 中是用 System.CLSCompliantAttribute 类来标识一个集合或者类是否是符合 CLS 规范的 在 System.CLSCompliantAttribute 的构造器中有一个 Boolean 型的返回值 代表了与之相关联的项是否符合 CLS 规范 2.3 开 发 工 具 .NET 为使用与开发人员提供了功能强大 种类丰富的管理与开发工具 同时它们 也是.NET 框架提供的服务 我们将它们列在下面 正是由于有了它们的支持.NET 才 变得如此强大 1. Visual Studio.NET 是.NET 的核心开发工具 包括微软提供的各种开发语言 其中有 Visual C# 2. Assembly Generation Utility (al.exe) 用来建立集合的工具 它能够将资源文件 或 MSIL 格式的文件转换为带有内容清单的集合 3. Windows Forms ActiveX Control Importer (aximp.exe) 完成 COM 类库中类型定 义的转换 使 ActiveX 控件能够在 Windows 窗口控件上使用 4. Code Access Security Policy Utility (caspol.exe) 在用户与机器水平上修改安全策 略
5. Software Publisher Certificate Test Utility( Cert2 spc.exe):用于从X509证书中生 成软件出版证明书(SPC) 6. Certificate Manager Utility( certmgr.exe):管理证书、证书信任列表和证书回收列 7. Certificate Verification Utility( chktrust. exe):检查证书签名的合法性。 8. Runtime Debugger( cordbg. exe):运行时调试器,是一个命令行程序,帮助开发 人员发现和调试基于CLR的应用程序中的错误 9. Global Assembly Cache Utility( gacutil. exe):允许你浏览与操纵全局集合缓存中 内容的命令行程序。 10. MSIL ASSembler( ilasm. exe):MSIL汇编程序,协助设计与实现MSIL生成器的 程序。 1l. MSIL DISassembler( ildasm. exe)MSIL反汇编程序,与 ilasm. exe共同使用,将 由MSIL代码产生的 Portable Executable文件转换为文本文件。 12. Installer Utility( installutil.exe):用来安装与卸载服务资源 er( Ic. exe):产生可包含在可执行二进制文件中的二进制资源文 件 14. Certificate Creation Utility( makecert. exe):生成Ⅹ.509证书与用于数字签名的公 用与私有密钥 15. Permissions View Utility(permviewexe):通过一个集合浏览许可集的工具 16. Peverify Utility( peverify. exe):检查中间语言与元数据是否符合类型安全认证要 求 17. Assembly Registration Tool( RegAsm.exe):读取集合中的元数据并加上必要注册 表入口信息,使得COM客户透明地建立CLR的类。 es regist 服务注册工具,它完成执行以下功能: 装载与注册一个集合,为现有的COM+1.0应用生成、注册与安装类库。 19. Resource File Generator Utility( Resgen exe):资源文件生成器,用来将文本文件 和XML格式的资源文件转换为CLR的二进制文件 20. Secutil Utility( SecUtil. exe):使得从集合中抽取的安全信息更加容易 21. Set Registry Utility( setreg. exe):改变注册表中公开密钥密码系统的设置。 22. Assembly Cache Viewer( shfusion dl):允许你使用 Windows浏览器察看与操作 全局集合缓存中的内容 23. File Signing Utility( signcode exe):为PE( portable executable)文件做标记。赋予 程序员在组件安全约束的基础上对安全性有更多的控制权。 24. Shared Name Utility( Sn. exe):帮助程序员以共享名称建立集合 25. Soapsuds Utility( SoapSuds.exe):使用远程技术帮助你编译与Web服务相通信的 客户应用。 26. Isolated Storage Utility(storeadm.exe):一种用来管理隔离存储区的命令行工具。 27. Type Library Exporter(( TIbExp.exe):命令行程序,生成由集合名称指示的包含集 合中公共类型定义的类库
5. Software Publisher Certificate Test Utility (Cert2spc.exe) 用于从 X.509 证书中生 成软件出版证明书 SPC 6. Certificate Manager Utility (certmgr.exe) 管理证书 证书信任列表和证书回收列 表 7. Certificate Verification Utility (chktrust.exe) 检查证书签名的合法性 8. Runtime Debugger (cordbg.exe) 运行时调试器 是一个命令行程序 帮助开发 人员发现和调试基于 CLR 的应用程序中的错误 9. Global Assembly Cache Utility (gacutil.exe) 允许你浏览与操纵全局集合缓存中 内容的命令行程序 10. MSIL Assembler (ilasm.exe) MSIL 汇编程序 协助设计与实现 MSIL 生成器的 程序 11. MSIL Disassembler (ildasm.exe) MSIL 反汇编程序 与 ilasm.exe 共同使用 将 由 MSIL 代码产生的 Portable Executable 文件转换为文本文件 12. Installer Utility (installutil.exe) 用来安装与卸载服务资源 13. License Compiler (lc.exe) 产生可包含在可执行二进制文件中的二进制资源文 件 14. Certificate Creation Utility (makecert.exe) 生成 X.509 证书与用于数字签名的公 用与私有密钥 15. Permissions View Utility(permview.exe) 通过一个集合浏览许可集的工具 16. Peverify Utility(peverify.exe) 检查中间语言与元数据是否符合类型安全认证要 求 17. Assembly Registration Tool(RegAsm.exe) 读取集合中的元数据并加上必要注册 表入口信息 使得 COM 客户透明地建立 CLR 的类 18. Services Registration Tool (RegSvcs.exe) 服务注册工具 它完成执行以下功能 装载与注册一个集合 为现有的 COM+1.0 应用生成 注册与安装类库 19. Resource File Generator Utility(ResGen.exe) 资源文件生成器 用来将文本文件 和 XML 格式的资源文件转换为 CLR 的二进制文件 20. Secutil Utility(SecUtil.exe) 使得从集合中抽取的安全信息更加容易 21. Set Registry Utility(setreg.exe) 改变注册表中公开密钥密码系统的设置 22. Assembly Cache Viewer(shfusion.dll) 允许你使用 Windows 浏览器察看与操作 全局集合缓存中的内容 23. File Signing Utility(signcode.exe) 为 PE (portable executable)文件做标记 赋予 程序员在组件安全约束的基础上对安全性有更多的控制权 24. Shared Name Utility(Sn.exe) 帮助程序员以共享名称建立集合 25. Soapsuds Utility(SoapSuds.exe) 使用远程技术帮助你编译与 Web 服务相通信的 客户应用 26. Isolated Storage Utility(storeadm.exe) 一种用来管理隔离存储区的命令行工具 27. Type Library Exporter(TlbExp.exe) 命令行程序 生成由集合名称指示的包含集 合中公共类型定义的类库
28. Type Library Importer( TIblmp.exe):将COM类库中的类型定义转换为在CLR 中与元数据格式一致的类型定义。 29. Web Service Utility( WebServiceUtilexe)}:帮助建立 ASPNET Web服务与客户 30. Windows Forms class viewer( wincv. exe):能够在某种査找模式下快速查找类或 者类序列的信息。 31. Windows Forms Designer Test Container( windes.exe):允许开发人员测试开发出 的视窗窗体控件在设计时的行为 32. XML Schema Definition Tool( xsd. exe):XML计划定义工具 24小结 本章解释了与NET有关的概念并简要介绍了一些相关的技术。在了解了NET的 结构之后,我们重点讨论了公用语言运行时环境和公用语言规范,最后给出了NET开 发工具的清单 在完成本章的学习之后,你已经了解了有关C#运行环境的相关知识,这将为你深 入学习C#打下良好的基础。从下一章开始,我们将进入实际的编程实践中,您将会发 现关于C#的更多更有趣的东西。 复习题 (1)NET的结构由哪四部分组成? (2)请简要总结CLR的作用。 (3)“可操控执行”的含义是什么? (4)NET是怎样解决传统 Windows程序设计中DLL的版本问题的? (5)什么是CLS,它的范围是怎样确定的?
28. Type Library Importer (TlbImp.exe) 将 COM 类库中的类型定义转换为在 CLR 中与元数据格式一致的类型定义 29. Web Service Utility(WebServiceUtil.exe) 帮助建立 ASP.NET Web 服务与客户 30. Windows Forms Class Viewer(wincv.exe) 能够在某种查找模式下快速查找类或 者类序列的信息 31. Windows Forms Designer Test Container(windes.exe) 允许开发人员测试开发出 的视窗窗体控件在设计时的行为 32. XML Schema Definition Tool(xsd.exe) XML 计划定义工具 2.4 小 结 本章解释了与.NET 有关的概念并简要介绍了一些相关的技术 在了解了.NET 的 结构之后 我们重点讨论了公用语言运行时环境和公用语言规范 最后给出了.NET 开 发工具的清单 在完成本章的学习之后 你已经了解了有关 C#运行环境的相关知识 这将为你深 入学习 C#打下良好的基础 从下一章开始 我们将进入实际的编程实践中 您将会发 现关于 C#的更多更有趣的东西 复习题 1 .NET 的结构由哪四部分组成 2 请简要总结 CLR 的作用 3 可操控执行 的含义是什么 4 .NET 是怎样解决传统 Windows 程序设计中 DLL 的版本问题的 5 什么是 CLS 它的范围是怎样确定的