C /CLI

面对C /CLI,很多人的第一个问题自然是“什么是C /CLI”

,我个人喜欢将其看作是位于静态程序设计和动态程序设计

之间的一座桥梁。C /CLI这个名称本身就包含着一组术语—

—而其中最重要的术语却是最不明显的那一个。

首先来看第一个术语“C ”,这当然指的是由Bjarne

Stroustrup在Bell实验室时发明的C 编程语言。它所支持的

是一种为代码执行速度和执行体所占空间所高度优化的静态

对象模型。除了堆内存分配以外,它不支持在运行时对应用

程序进行任何的更改。它允许我们对底层机器进行无限的访

问,但对于正在运行的程序中的活动类型、以及相关的程序

基础构造,它的访问能力却非常有限、或者根本就不可能。

它是一门非常成功的编程语言,但是它却不能适应目前的Web

编程环境以及相关的安全问题——这已经成为目前程序设计

中一个越来越重要的考量。

再来看第三个术语“CLI”,即通用语言基础构造(Common

Language Infrastructure),这是一个支持动态组件编程

模型的多层架构。在许多方面,它所表示的对象模型和C 的

完全相反。在CLI中,存在一个运行时软件层(即虚拟执行环

境)运行在应用程序和底层操作系统之间,应用程序代码对

底层机器的访问会受到相当严格的限制;事实上,CLI根本不

允许安全环境中的代码进行这样的访问。但另一方面,CLI却

允许我们对正在运行的程序中的活动类型、以及相关的程序

基础构造进行完全的访问,甚至允许我们动态构造额外的类

型和程序基础构造。这些灵活性的获得当然伴随有相当的空

间(执行体所占空间)和时间(程序执行效率)代价,但是

它却解决了日益增长的基于连接的计算环境中所面临的问题

和需要。
最后,再来看第二个术语,即中间的斜线“/”,它往往为人

们所忽略。其表示对C 和CLI的一种绑定(binding),它正

是C /CLI设计的焦点所在。据此,对于“什么是C /CLI”这

一问题可能的一种答案便是“它是对静态C 对象模型和动态

CLI组件模型的一种绑定”。

对于C /CLI,一个C 程序员只需要将其添加到她已有的编程

工具箱中就可以了。要成为一个C /CLI程序员,你无需放弃

任何已有的东西,虽然你要步入一个新的技术世界,你仍然

需要学习它——但愿你能享受这一过程,至少我知道我是这

样的。由此观之,我们还可以将C /CLI看作是一扇通往另一

个世界的大门。

C /CLI将动态的、基于组件的编程模型和ISO-C 集成在了一

起,这种集成非常类似于我们当年在Bell实验室对使用模板

的泛型编程和当时的C 所做的集成。在两种情况下,你已有

的代码投资和编码经验都将得到保留。这是我们设计C /CLI

时一个基本的需求。

通用语言基础构造(CLI)是一个多层的体系架构,它为所有

CLI语言提供了各种各样的服务。例如CLI中定义了一个通用

类型系统(Common Type System,简称CTS),而各个CLI语

言都提供了自己对CTS的一个映射。该类型系统由一个根基类

开始被组织为一个完整的类继承体系。实际上,每一个CLI类

型都是一个类——不仅包括像integer、double这样的数值类

型,而且也包括字面常量(literal constant)。每一个

CLI类型(或者值)都表示一种Object(所有CLI类型的根基

类),比如数值3.14159、比如字符串常量"Homer Simpson"

 

单一的根基类为运行时类型查询和代码生成(通常被称为反

射)提供了支持机制[译注2],这是ISO-C 所缺乏的。我们将

在今后一系列文章中详细讨论它们给CLI带来的动态编程特性

 

除此之外,CLI还支持一种被称作特性元数据(attribute

metadata)的构造,它允许我们定义一些特性类,然后将其

关联在CLI类型和当前正在运行的程序构造上——这有效地扩

展了内建于CLI中的类型和程序构造。这些用户定义的特性也

可以通过反射机制来获得,应用程序则可以根据它们的值来

进行条件逻辑判断。这也是C /CLI为C 带来的动态组件编程

的一部分。再次强调一遍,类型反射和特性将在我们的专栏

中得到深入的讨论。

AntonlioX(做人要厚道) 于 2005-7-16 14:08:53
那么,对于大家来说怎样学习C /CLI呢?学习C /CLI的其中

一个要点便是学习底层的通用类型系统(CTS),它包括以下

三种类型:

 

1. 多态引用类型,其用于所有的类继承。我们将在早期的

一些专栏文章中讨论它们。

2. 非多态值类型,其用于实现一些类似于数值类型那样的

、对运行时效率要求比较高的类型。我们将其放在引用类型

之后讨论。

3. 抽象接口类型,其用于定义一组供引用类型或者值类型

实现的操作。接口为多继承提供了一种别样的设计模式。我

们也将有一系列专栏文章来讨论它们。

 

将CTS映射为一组语言内置类型对于所有的CLI语言都适用,

虽然各种语言所使用的语法各不相同。这也是一门CLI语言所

要面对的第一个设计层面。例如,在C#中,我们可以用以下

代码来定义一个抽象基类型Shape(一些具体的几何对象将继

承自它)。

public abstract class Shape {…}

而在C /CLI中,我们用下面的代码来定义同样的类型。

public ref class Shape abstract {…};

除了语法差异之外,两种声明的实际表示完全相同。类似地

,在C#中,我们可以用下面的代码来定义一个具体类Point2D

public struct Point2D {…}

而在C /CLI中,我们用下面的代码来定义同样的类型。

public value class Point2D {…};

我们对语法的选择基于如下的出发点:以一种直观的设计视

角将CLI类型和ISO-C 类型紧密地集成在一起。

 

因此,简单地说一种语言比另一种语言更接近底层CLI并不正

确。相反,每一门CLI语言都只是表达了自己对底层CLI对象

模型的一种视图。

 

 

 

 

 

学习C /CLI的第二个要点是学习我们选择直接提供给程序员

操作的那些底层CLI元素。例如,CLI为所有语言都提供了垃

圾收集服务。一门语言不能选择是否支持垃圾收集,而只能

选择如何更好地提供该服务。

 

在CLI中,一个引用类型的所有对象都只能被分配在CLI托管

堆上。这意味着C /CLI支持两种动态堆——本地堆(没有任

何形式的自动内存回收机制),和CLI托管堆。对于这两种动

态堆,开发人员通常要用某种形式的new操作符来分配对象;

如果操作成功,对象在堆中初始位置的地址将被返回。但是

两者又有所区别,这是因为CLI托管堆中对象的位置有可能在

垃圾收集器的清除以及随后的压缩中被重新调整。如果一个

对象的位置被重新调整,那么CLI运行时中所含的其中一项服

务会透明地更新所有引用该对象的指代品(thingee)。

 

这就使得我们面临着一种困难的选择:我们是将这些指代品

称为指针,并且继续用指针的语法来表示它们呢?还是引入

一种新的类似的语法来表示它们需要特殊的处理?我们最后

决定采用后者,看下面的代码:

N *pn = new N;

R ^rn = gcnew R;

这里,N表示一个本地类型,而R表示一个CLI引用类型,帽子

状的符号(^)表示相关的地址是一个托管堆上的追踪句柄(

tracking handle)——也就是说,对象位置的任何重新调整

都会被CLI所追踪,相应的句柄也会被透明地更新。其中关键

字gcnew在这里被用作与CLI托管堆打交道的new表达式。

 

值类型事实上也可以位于托管堆上,虽然这并非必须。当它

们作为一个引用类型的成员时,就会出现这种情况。如果我

们允许获取一个引用类型内部成员的地址,那么本地指针也

是不合适的,因为这些成员的位置也需要被追踪。一种解决

方法是简单地禁止该项功能。这样语言当然会变得更加简单

,但是同时语言也会变得更弱——例如我们将不能通过增长

元素的地址值来遍历CLI数组,这是因为CLI数组是一个引用

类型,其内的元素都位于托管堆上。不提供这样的功能意味

着CLI数组将不能适用于标准模板库(STL)中的iterator模

式以及泛型算法。对于一个C 程序员来说,这是不可接受的

 

支持获取可能位于托管堆中的值类型的地址同样需要引入一

种追踪指针,我们称之为追踪内部指针(tracking

interior pointer)。另外,我们还支持追踪引用

(tracking reference)这样的概念——它具有类似本地引

用的别名语义,但是它会在必要的时候被CLI透明地更新。最

后,我们还支持一种固定指针(pinning pointer)的概念,

它可以在该指针的作用范围内阻止垃圾收集器移动其所引用

的对象。

 

这些新的符号及其表示的复杂的间接类型是在我们对托管堆

反复学习和认识之后产生的。面对生存期短暂的托管堆对象

,我们需要某种精巧的方式来认识和使用它们,我们相信这

些额外的间接类型可以给大家很多帮助。我们将在今后的专

栏文章中详细讨论它们。

 

我们在此对一门CLI语言所选择的第二个设计层面表示了其对

底层CLI实现模型的一层映射。选择什么样的映射取决于该编

程语言定位于什么样的程序及程序员模型。当你选择一门CLI

语言进行编程的时候,你实际上也是在选择遵从一种程序员

模型。我们对于C /CLI程序员的定位是那些历练较深的系统

程序员,这些程序员通常所面对的任务是为高层的商业逻辑

提供基础性的构造和关键性的应用,这时候她就必须要同时

考虑系统的扩展性和性能,因此必须对底层CLI有一个系统级

的视角。

 

 

 

 

学习C /CLI的第三个要点是学习那些非CLI本身所直接提供的

功能特性。这也是每一门面向CLI的语言所要面对的设计选择

,也是各种CLI语言之间相互区分的一种体现。

 

例如,CLI本身并不支持多类继承(multiple class

inheritance,简称MCI),而只支持多接口继承和单类继承。

但Eiffel语言在设计其面向CLI的实现时就选择了支持源代码

级的多类继承。这需要一种巧妙、甚至是复杂的设计将源代

码级的多类继承映射为底层CLI的单类继承模型。Eiffel语言

的设计人员认为这种映射对于CLI平台上的Eiffel程序员是一

个利好的元素。

 

在此C /CLI的第三个设计层面上,我们没有采用多类继承的

方案。其中一个原因是我们不能说服自己多接口继承模型有

任何不够简单或者优雅的地方。我们没有足够的经验来确定

哪种方案绝对的优秀,但是我的直觉告诉我多类继承(MCI)

是一个死胡同。我们在此设计层面上的主要关注点在于为那

些CLI本身所欠缺的地方提供一些额外的解决方案,我们主要

集中在以下三个方面:

 

1. 为某些CLI要求手动干预的地方提供一种自动化的解决方

案,例如确定性终止化操作(deterministic finalization

)和稀有资源释放。

2. 提供一些特殊的类成员函数——例如拷贝构造器和拷贝

赋值操作符,以及在CLI直接支持的操作符的基础上再为一些

操作符提供一些扩展支持——例如用来支持函数对象

(function object)设计模式的调用操作符“()”。

3. 提供一种静态的参数化机制来支持设计适用于CLI类型的

标准模板库(STL),这是因为CLI中的泛型机制在我们来看

对于当代的参数化设计是不够的——虽然我们也支持它们。

 

以上几点在我们的系列专栏中都将有相关的讨论。特别地,

我们将会详细阐释C /CLI中的模板和泛型机制。

 

 

 

 

 

C /CLI的第四个设计层面在于它选择了“集成”而非“替换

”的策略,这是C 以及一些语言所独有的,而其他一些语言

则没有这样做,例如Visual Basic采取的就是“替换”的策

略。一个合法的C 程序是可以顺利通过C /CLI编译,并且可

以正常运行的。我们认为这对于我们的程序员是一项基本的

需求。

 

谈到C /CLI的第四个设计层面,这究竟是什么意思呢?它表

示我们对C /CLI语言规范和ISO-C 所做的深入的集成。例如

,除了我们扩展支持集合使其也适用于统一的CLI类型系统,

表达式评估的标准转换集合与重载函数的辨析都和ISO-C 的

相同。当我们引入模板和多继承机制时,我们也应用了同样

的扩展策略。这些都是在语言中稍显抽象的部分,在某种程

度上我们已经使它们的行为变得更加直观,免除了程序员深

入算法细节的需要。但我们仍会在系列专栏中花费笔墨关注

一些主要的变化,例如对字面常量(literal)字符串的处理

 

在C /CLI未来的版本中,我们希望为本地类型和CLI类型提供

更为无缝的集成。在目前的实现中,仍然存在许多不能跨越

的壁垒。例如,我们现在还不能直接在一个CLI类中声明一个

本地类的实例对象;相反,我们必须声明一个指向那个本地

对象的指针,然后在CLI类的构造器/析构器对中处理对它的

内存分配与释放。我们希望将来能够透明地处理它们。类似

地,如果可以方便地编写下面的代码就更好了:

N^ n = gcnew N;

R* pn = new R;

即将一个本地类透明地放在垃圾收集控制的托管堆中,以及

将一个CLI引用类型透明地放在本地堆中,并使它们正常运行

。这些是我们对于C /CLI未来的一些设想和愿景。随着这些

设想的实现,我们也会在我们的专栏中讨论它们。


AntonlioX(做人要厚道) 于 2005-7-16 14:09:08
最后,再回答一个大家经常问到的一个问题,“我为什么要

学习C /CLI”?首要的原因是C /CLI将会为你进入CLI所表示

的动态组件编程模型领域提供一张第一等的入口签证。如果

你像我一样认为这将成为越来越重要的一种编程模型,并且

如果你是一个历练较深的程序员,那么C /CLI就是你想要的

一个语言工具。如果你不喜欢某些地方,或者发现某些东西

很难表达,那么请告诉我们。我们代表着一个动态编程社区

,C /CLI也会持续不断地前进。

 

在C /CLI之前,如果我们希望或者需要在CLI所表示的动态编

程领域工作,那么我们只能放弃使用C [译注3],这意味着我

们同时放弃了我们现存的代码库和编码经验。有了C /CLI之

后,我们就拥有了一条沿着C 向上的移植路径。这是学习C

/CLI的第一个原因。

学习C /CLI的第二个原因在于它允许我们访问整个CLI框架类

库,包括用户界面,线程,网络,XML,ADO.NET,ASP.NET

,以及Web服务这个宽广诱人的世界。另外,在即将推出的

WinFX中,一个封装了整个操作系统的类库体系(包括应用程

序及其执行空间[译注4])也会被收编在CLI门下。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值