CLR约定的本性决定了它适合于一种独立于任务或编程语言的编程模型,。CLR的编程模型比COM的更为精炼,它尤其强调类型中心(type-centric)。你的程序处理的每个实体都源自类型,包括对象、值、字符串、基本数据和数值。编程模式的类型中心是必需的,这是CLR提供的一个关键服务,即代码能被检验是类型安全的(type-safe)。这样,防止对象约定之外的恶意代码劫持对象的引用,并调用其方法。
尽管开发者可以重新编译现存的C++程序,用于CLR,但是,绝大多数用于CLR的新程序是通过更高级别的抽象编写的。CLR的编程思想就是一切都是类型、对象或者值。为此,CLR提供一套服务,统称为托管执行(managed execution)。在托管执行下,CLR是万能的,拥有运行程序各方面的完整信息。其中,包括方法中局部变量的状态和生存期的知识;还包括用于每一个堆栈帧(stack frame)的代码的开始位置;以及所有现存对象和对象引用的知识,包括可达性信息(reachability information)。
CLR程序员被鼓励放弃过去非托管的编程风格,特别是摒弃显式地内存管理,而采用分配和使用类型实例。同时,程序员还被鼓励放弃线程管理,而采用CLR工具,执行并发方法。
对于那些坚持要求控制程序体的读者,不妨回顾一下从DOS的平台到Windows NT的演变。最初,也有一些开发者对从物理内存与中断转向虚拟内存与线程感到太慢或者太受限制。同样,CLR也将面临着类似的争论。
只有时间能说明CLR是不是“太过抽象”;不过,笔者坚信,迁移到托管执行环境[例如,CLR或者Java虚拟机(JVM)],这是一个进步,而不是倒退。一直以来,当程序员面临生产率(productivity)和可控性(control)的选择时,随着时间的推移,能够让他们拥有更高生产率的技术更可能胜出。图1.1展示了这两个因素之间的关系。
新编程模型的另一个关键方面是对元数据的很强的依赖性。并且,元数据对于运行在CLR内部或外部的程序是可访问的,这独立于元数据本身被用来将CIL翻译为本机代码这个事实。因此,运行在CLR内部或外部的任何程序也都能够访问元数据。依赖于元数据的反射(reflect)能力使得程序可以被其他程序生成,而不用人工编写。生成编程(Generative programming)算是比较新的课题。然而,生成编程的大多数应用程序通常将某个程序的元数据作为输入,并且发射(emit)其他程序作为输出。由于输入程序的元数据较容易访问,使得构建生成架构变得相当容易。
CLR也通过名为CodeDOM的工具支持生成编码。CodeDOM允许C#、VB.NET和JavaScript程序在内存中构造,并以强类型对象模型,而不是文本流。CodeDOM使发射源代码的生成程序(generative program)能够尽可能地延缓输出。此外,CodeDOM支持代码的内存中编译,并且,容许针对常用的高级编程语言,引入新的生成技术(包括新的编程语言编译器),而不是CIL与元数据特性的低层方面。
CLR是加载和执行代码的平台。然而,如果不借助编程语言,很难将CLR(或者它所蕴含的编程模型)讨论清楚。一般情况下,只要编译器能够发射CLR元数据和CIL的编程语言,CLR都可以支持。编程语言犹如冰淇淋的口味儿,各人有不同的喜好。在这方面,本书尽可能地避免特定语言的讨论。不过,我们必须通过某种编程语言来展示CLR的不同侧面和特征。
本书的示例一般采用C#。之所以选择C#,是因为它是这个平台中事实上的标准语言,这点可以从其大量的支持工具、文档、SDK范例上得以证明。值得注意的是,尽管C#自身的语法大量地借鉴了C、C++以及Java的特点,但是,C#终究是另一种编程语言,它有自己的一套基于CLR的约定和构造。表1.1列出了.NET Framework软件开发工具包[software development kit(SDK)]1.0版明确支持的5种编程语言的比较情况。
我们走到哪儿了
CLR是组件软件的一个发展阶段,像其前身COM一样,CLR支持基于强类型约定的组件的集成。不同于COM的是,这些约定都是基于逻辑结构的,这意味着其中没有低层物理数据的表示形式。虚拟化让我们朝着纯粹语义约定的神圣目标(Holy Grail(原文为Holy Grail,是指传说中耶稣在最后晚餐中用过的圣杯))迈进了一步。组件约定是通过CLR元数据描述的。CLR元数据是一种可扩展的、机器可读的交换格式,它在基于CLR的程序和架构中随处可见。
表1.1 .NET语言特征
特征 |
VB.NET |
JScript |
C# |
C++ |
ILASM |
编译器 |
VBC.EXE |
JSC.EXE |
CSC.EXE |
CL.EXE |
ILASM.EXE |
CodeDOM支持 |
是 |
是 |
是 |
否 |
是 |
动态地添加成员 |
否 |
是 |
否 |
否 |
否 |
迟绑定 |
自动 |
自动 |
手工 |
手工 |
手工 |
自定义值类型 |
是 |
否 |
是 |
是 |
是 |
大小写敏感 |
否 |
是 |
是 |
是 |
是 |
无符号整型 |
否 |
是 |
是 |
是 |
是 |
方法重载 |
是 |
是 |
是 |
是 |
是 |
操作符重载 |
否 |
否 |
是 |
是 |
N/A |
C风格指针 |
否 |
否 |
是 |
是 |
是 |
本机/非托管指针 |
否 |
否 |
否 |
是 |
否 |
代码验证 |
总是 |
总是 |
可选 |
从不 |
可选 |
不透明的/非托管类型 |
否 |
否 |
否 |
是 |
是 |
模板/泛型 |
否 |
否 |
否 |
是 |
否 |
多重继承 |
否 |
否 |
否 |
是 |
否 |