本书为需要充分利用Microsoft.NET强大功能的开发人员提供了详尽的信息,深刻地论述了.NET Framework(.NET 框架)的精髓:公共语言运行库[Common Language Runtime (CLR)]。Box和Sells揭示了CLR的内部工作方式——CLR设计背后的基本原理,它能够解决的问题,以及CLR编程中类型的角色。并且,在帮助读者在对CLR工作机制有了更为完整的理解的同时,指导他们如何利用.NET Framework构建更好的应用程序。本书包含了很多实用细节,以及由Don Box提供的专家建议。主要有:CLR演变、.NET Framework的程序、CLR类型系统、用类型编程、对象和值、方法、显式方法调用、应用程序域、安全性和互操作性。
本书作者Don Box是微软公司的架构师,主要研究方向为第二代Web服务协议和程序设计模型。Don是软件集成技术方面的权威。在二十世纪九十年代,他为了CLR,积极筹建了组件对象模型[Component Object Mode(COM)]社团。他是简单对象访问协议[Simple Object Access Protocol(SOAP)]版本1.1规范的缔造者之一,同时他还是畅销技术专著《Essential COM》(Addison-Wesley,1998)、《Effective COM》(Addison-Wesley,1999)以及《Essential XML》(Addison-Wesley,2000)(以上作品均已由中国电力出版社出版)的作者及合著者。
第一章 CLR是一个更好的COM
COM回顾
公共语言运行库
编程模型的演进
我们走到哪儿了
第二章 组件
模块定义
程序集定义
程序集名字
公钥和程序集
CLR加载器
将名字解析成位置
版本控制
我们走到哪儿了
第三章 类型基础知识
类型概述
类型和初始化
类型和接口
类型和基类型
我们走到哪儿了
第四章 用类型编程
运行时的类型
用元数据编程
特殊的方法
元数据和可扩展性
我们走到哪儿了
第五章 实例
对象和值的比较
变量. 参数和字段
相等与同一
克隆
装箱
数组
对象生存期
终结
我们走到哪儿了
第六章 方法
方法和JIT编译
方法调用和类型
接口. 虚方法和抽象方法
显式方法调用
间接方法调用和委托
异步方法调用
方法终止
我们走到哪儿了
第七章 高级方法
动机
作为方法调用的消息
堆栈和消息传递
代理类型
消息过程(回顾)
对象和上下文
上下文和中断
我们走到哪儿了
第八章 域
执行范围和CLR
用AppDomain编程
AppDomain事件
AppDomain和程序集解析器
AppDomain和代码管理
AppDomain和对象(回顾)
我们走到哪儿了
第九章 安全性
组件和安全性
证据
策略
权限
实施
我们走到哪儿了
第十章 CLR外部环境
内存
执行模式
非托管模块
加载CLR
作为COM组件的CLR
我们走到哪儿了
发生了什么?
在1998年, Microsoft公司在圣地亚哥(San Diego)举办了专业开发人员大会[Professional Developer's Conference(PDC)] . COM的杰出人物Charlie Kindel在全会上预言:"将不再有GUID, 不再有HRESULT, 不再有IUnknown. "他和Mary Kirland进一步展示了CLR的基本架构, 也就是COM+运行时(COM+ Runtime). 在会议的后半段, Nat Brown和David Stutz演示了使用Visual Basic和Java进行跨语言的继承. 参会者还领到了有关这个非常奇妙演示的CD, 里面包含了该编译器的原始版本. 他们可以回到家中, 重新进行这个演示. 现在是2002年的2月, 这项技术终于得以正式发布.
Microsoft平台的演变可以用两天时间进行划分. 1993年7月27日, Windows NT3.1的发布标志着DOS时代的终结, 2002年2月13日, 公共语言运行库[Common Language Runtime(CLR)]作为.NET Framework的一部分进行发布, 标志着COM时代的终结.
.NET Framework 是一个用于软件集成的平台. 从根本上讲, .NET Framework提供了两个核心的集成技术:一个是公共语言运行库(CLR), 它被用来将软件集成到一个单独的操作系统进程中 , 另一个则是XML Web Services, 它被用来在Internet范围内进行软件集成 . 它们都是基于相同的思路, 也就是强类型的协定(strongly typed contract)和封装. 不过从根本上讲, 它们属于不同的技术, 可以相互独立地应用. 你可以选择XML Web Services, 而不是CLR(事实上, 许多Web Services产品就已经这样做了), 当然, 你也可以在没有XML Web Services的情况下采用CLR, 这样能够更好地利用CLR相关的特征, 例如, 代码访问的安全性, 或者高级的内存管理的实用部件. 不管怎么说, CLR和XML Web Services都将成为Microsoft开发平台的中心, 相关开发经验的积累只是时间问题.
CLR和XML Web Services都强调组件之间的强类型协定. 这两项技术都需要开发者根据类型定义或者协定描述组件之间的相互关系. 在这两种技术中, 贯穿在这些协定应用的关键概念是:元数据(metadata)和虚拟化(virtualization).
CLR和XML Web Services都依赖高保真的(high-fidelity) . 无所不在的以及可扩展的元数据, 通过这些元数据传达程序员的意图. 元数据向将要使用CLR组件或者XML Web Services的开发人员传达了程序的基本结构和类型关系.
同样重要的是, 无所不在的元数据把组件开发者在编写代码时的意图通知给相应的工具和底层平台.
同组件的完成不透明相比, 元数据指引的"洞察力"允许平台为其提供更加丰富的支持 . 例如, XML序列化器 将捕获元数据中对象到XML映射的不同方面. 至于XML流的表示方式, 开发人员更倾向于通过声明的元数据, 而不是显式的编写代码 .
体现CLR和XML Web Services协定的第二个关键思路就是虚拟化的概念. 这两个技术都强调将语义部分与物理实现的细节分离开来. 特别是这两个技术的元数据作用于抽象结构层, 而不是依据底层数据的表示和实现技术. 当开发者在这个"虚拟"层指定了组件之间的协定, 底层平台就能够以最有效的方式传递协定. 例如, 为了根据某个抽象数据模型传递Web Services的协定, 通道(plumbing)既可以采用高效的二进制数据表示方式, 以提高性能, 也可以采用基于文本的XML 1.0表示方式, 以最大限度地提高协作性 .
因为协定是虚拟化的, 所以, 协定的具体细节可以依据开发后的特性, 在运行时绑定.
由于这部分 完全集中在CLR上, 因此, CLR的工作定义是有序的. CLR根本就是一个加载器, 它将你的组件载入到在一个操作系统进程中. CLR代替COM的CoCreateInstance和Win32的LoadLibrary, 成为代码的主要加载器.
CLR作为代码的加载器, 与前任COM和Win32相比, 它提供了更多的服务. CLR具有版本感知(version-aware)的特征, 它能够提供版本策略和代码存放的灵活配置 , CLR加载器具有安全感知的特征, 它是执行安全策略的重要部分, CLR加载器具有类型感知的特性, 对于显式的管理和独立于编程语言的类型创建, 它能够提供更丰富的运行环境. 总之, CLR加载器是一种高级的组件技术, 将取代COM, 成为Microsoft主要的主存内集成策略.
编译器将生成CLR的新的文件格式 , 这样CLR就可以懂得许多编程语言. 注重编程语言的人将CLR看成是为编译器作者提供了关键的生成程序块(key building blocks)技术, 而生成程序块降低了编译器实现的复杂度 . 相比之下, 注重系统的人往往将编程语言看成是外在的东西, 或者是基于CLR底层构件之上的"皮肤". 笔者坚定地倒向后面的阵营. 然而, 编程语言是必需的透镜, 甚至底层系统也要通过它来观察CLR. 正是基于这种观点, 本书的示例采用了多种编程语言, 理由就是元数据与代码的二进制转储形式(binary dump) 才是CLR难以理解的地方.
关于本书
我下了很大的功夫来提高本书的可读性, 以适合更多的读者. 然而, 我一贯的写作风格都是简约式的, 这使得"Don Box"的书面临着易读性方面的挑战. 我的写作经验证明, 我不擅长撰写教程或入门级的读物. 我能够做好的事情, 就是通过书本形式再现我对世界的看法. 所以, 你在阅读Don Box的书时, 需要多读几遍, 才能领悟其中的用意.
前一段的意思是本书不适宜作入门读物. 如果你试图通过本书学习.NET Framework编程, 恐怕会让你失望. 我推荐你不妨先读一下Stan Lippman的《C# Primer》(2002年由Addison-Wesley出版), 或者Jeffery Richter的《Applied .NET Framework Programming》(2002年由Microsoft Press出版), 然后, 你再阅读本书.
本书分为两卷:卷I主要阐述公共语言运行库(Common Runtime Language). 卷II将重点讨论XML Web Services. 虽然这两项技术都共享许多相同的核心技术, 但是, 假如将它们纳入一本书中, 着实让我为难.
本书是针对CLR第1版写的. CLR所用的一些内部技术可能会随着时间而逐步演化, 并且事实上可能改动很大. 特别是有关虚方法分发的细节就极有可能改变, 而这部分内容主要是为了那些想知道vptr去向的COM开发人员而设的, 在本书中也占着相当大的篇幅. 也就是说, 本书所阐述的基本概念要固定下来, 还需要假以时日.
我在整本书的代码中采用了断言, 以强化程序的预期状态. 在CLR中, 通过System.Diagnotics.Debug.Assert执行断言. 该方法接受一个布尔表达式作为参数. 如果表达式被运算为false, 则断言失败, 程序将停止, 并发出不同的错误信息. 为了提高可读性, 本书所有程序都采用短格式, 即使用Debug.Assert. 它假定System.Diagnostics命名空间前缀已经被导入.
我认为.NET并不很在乎具体的编程语言. 在我日常基于CLR的编程工作中, 大约50%的程序是用C#写的, 40%为C++, 剩下10%则是ILASM. 本书绝大多数的示例采用C#编程语言, 除了个别概念或技术, 需要更为简明的语法表示. 虽然有些章节看上去是语言相关的, 但实际上没有一章真正是这样的. 尽管本书几乎所有部分都适用于C++, 但出于推广C#的目的, 我还是选择了C#, 使本书更容易被读者接受.
本书重点讨论公共语言运行库(CLR), 共分为10章.
·第一章--CLR是一个更好的COM:本章从组件对象模型[Component Object Model(COM)]开发人员所面临的问题入手, 讲述了CLR如何采用虚拟化(virtualization), 以及无所不在的. 可扩展的元数据(metadata), 解决这些COM问题, 从而最终取代COM.
·第二章--组件:从根本上讲, CLR是OS和COM加载器的替代品. 本章讨论了代码是如何封装和加载的, 它们与在Win32和COM世界中的情形大相径庭.
·第三章--类型基础:组件是代码和构成类型定义的元数据的容器. 本章重点讨论了通用类型系统[Common Type System(CTS)], 包括类型的组成部分, 以及类型是如何关联的. 这是首次出现源代码块的章节.
·第四章--用类型编程:在编程模型中, CLR将类型作为第一类概念. 本章讨论了CLR程序中类型的显式用法, 主要是元数据与运行时类型信息的角色.
·第五章--实例:CLR编程模型是基于类型. 对象和值的. 第四章讨论了类型, 本章则重点阐述对象和值. 特别是本章概述了这两种实例模型的差别, 包括值与对象在内存管理方面的不同.
·第六章--方法:所有组件之间的交互都是在方法调用中呈现出来的. CLR提供一系列的技术, 用于使方法调用成为清楚的行为. 本章将介绍这些技术, 从实时编译时的方法初始化开始, 直到类型异常时的方法终止.
·第七章--高级方法:CLR提供了强大的架构用来侦听方法调用. 本章剖析了CLR侦听的实用部件, 以及它对面向方面编程(aspect-orient programming)的支持. 这些实用部件是CLR比较超前的方面之一 .
·第八章--域:CLR采用AppDomain(应用程序域), 而不是OS进程, 来划分代码的执行范围. 本章从两个方面讨论AppDomain的角色, 即作为底层OS进程的替代品, 以及一个AppDomain与程序集解析器或加载器之间的交互. 熟悉Java的读者将发现Java加载器与它很相似.
·第九章--安全性:CLR一个主要优点就是提供安全运行的环境. 本章阐述了CLR加载器如何支持向代码授予特权, 以及这些特权如何被强制实施的.
·第十章--CLR外部环境:本书前九章都是讨论基于CLR编程模型的程序设计. 最后一章则关注该编程模型对外的方式, 以及它如何处理CLR外部世界.
致谢
在我妻子与孩子一如既往的支持下, 促使我顺利地完成这部书. 这里, 我要感谢他们在这部书一年多的写作期间所做的一切.
如果没有Chris Sells的工作, 这部书可能就无法完成. Chris是我的写作伙伴, 并在整个2001年的岁月里, 无论从精神上, 还是专业上, 都推动了这部书的撰写进程. 尽管Chris没有写过一段文字, 但他的努力在每一页都卓然可见.
感谢Microsoft公司CLR小组的Jim Miller. Miller慷慨地为本书写了序言, 这令我倍受鼓舞. 不过, 更为重要的是, Jim是CLR的ECMA规范的首席作者. 我认为, 这五个部分的ECMA规范是关于CLR最重要的文献. 在.NET Framework SDK的Tools Developer's Guide(工具开发者向导)文件夹中, 你可以找到这五个word文档. 这些文档揭示了CLR的许多内幕. 对于CLR, 我相信ECMA规范至关重要.
在撰写本书的过程中, 我所获得的大多数技术内幕, 都是同DOTNET邮件列表中的开发人员进行沟通得来的(参见http://discuss.develop.com). 该列表可以说是活跃于CLR编程社区的开发者与架构师的中心. 这里特别列出对我有帮助的人员:Brian Harry. Jim Miller. Dennis Angeline. Stevern Pratchner. Brent Rector. John Lam. Mike Woodring. Keith Brown. Peter Drayton. Brad Wilson. Jay Freeman和Sam Gentile.
如果没有审稿人, 本书的错误肯定更多. 这里感谢Dan Sullivan. Peter Drayton. Mike Woodring. Chris Sells. Stuart Celarier. Jay Freeman. Steve Vinoski. Stan Lippman. Robert Husted. Peter Jones. Mike Giroux . Vishwas Lele. Dan Green. Paul Gunn和Fumiaki Yoshimatsu. 特别是Brian Kernighan对本书早期的审校尤为重要. 他的那次审校令我重新评估本书的写作思路, 以及如何实现写作意图的方式. 如果没有Brian的审校, 就没有那次的重要修改. 谢谢你, Brian.
与以前一样, 总有一个"村落"造就了Don Box. 就这部书而言, 这个"村落"的成员有:Helga Thomsen. Sandy Deason. Barbara Box. Judith Swerling. David Baum. David Stromberg. Martin Gudgin. Mike Woodring. Fritz Onion. Shannon Ahern Ikeda. Ron Sumida. Tim Ewald和Aaron Skonnard.
Don Box
2002年2月
Yarrow Point, WA(华盛顿地区)
我以前在麻省理工大学[Massachusetts Institute of Technology(MIT)]时,曾经为3W协会(World Wide Web Consortium)工作。鉴于COM和CORBA是当时整个网络上最主要的面向对象的框架,于是我们决定同时研究它们。
我打电话给我们的Microsoft公司的代表,希望他能请人为协会成员讲解COM原理。同时我告诉他,我们协会成员的技术水平都很高,比较喜欢刨根问底;我们正致力于制订下一代的Web协议,并且通晓Internet上各种应用协议的细节;此外,我们曾经用C++或Objective C开发过一些非常大型的面向对象程序。
我特别希望他能够推荐Microsoft公司的专家。然而 ,我得到的答复是“关于COM,没有任何人能阐释得比Don Box更棒! ”。这也成了我认识Don的缘由。Don是我所见到的最好的教师:他不仅能够清晰地讲解,很好地辅以实验,写作能力也无可挑剔,而且,他还能够讲解得非常细致透彻,从宏观问题“为什么以那种方式构建这个体系结构?”,到细节问题“那个bit到底是在什么位置?”。就这样,Don教会我(连同其他成千上万的技术人员)什么是COM,为什么要使用COM,COM有什么问题。考虑到我们的实际工作,他还即兴将COM技术同CORBA技术,以及我们正在设计与构建的Web技术做了令人惊讶的比较。
后来,我离开了MIT和3W协会,加盟Microsoft公司,参与了列为最高机密的名为“COM+服务”的项目。这个项目在我的名片上是这样描述的:“Program Manager,Garbage Collection and Related Rubbish”。所有我们能够公开的(甚至在Microsoft公司内部)就是:它带有编程语言和分布式系统,还有一个垃圾回收器。在差不多四年多的时间中,我一直参与并致力于设计和构建现在推出的公共语言运行库(Common Language Runtime),目前仍为这个项目工作。我的主要工作有:IL(中间语言)设计、四种不同的实时编译器(JIT)、元数据、垃圾回收器、执行引擎以及ECMA标准(希望它能尽快成为ISO标准) 。
我本来自以为能够反过来教Don一些东西(我本人并不是较差的教师),但Don没有让我如愿以偿。他告诉我读一下这本书,于是我发现,对于我自己的产品,他竟然教了我所不知道的东西!我坚信,你也一定能从中受益匪浅。
Dr.James S.Miller
Microsoft公司
首席程序经理
公共语言运行库组