Shared Source CLI Essentials第一章第一部分

类别:.NET开发 点击:0 评论:0 推荐:

第一章           CLI组件模型介绍

21世纪的程序员有很多烦恼。

首先,优秀的软件比以前复杂多了。仅仅提供一个基于终端的简单命令提示符或一个字符用户界面已经不能被用户接收了;现在的用户需要包括各种优秀虚拟功能的丰富的图形化用户界面。软件相关的数据,已经很少有结构适合存储在本地系统的普通文件中的了;现在的情况是,计算机用户已经十分依赖软件所提供的查询和报表的功能,而为了满足用户的这些需求,常常必须使用关系数据库。而不断变化的业务情况要求对长期存储的数据进行的经常的修改也要求必须使用关系数据库。从前单机环境就能够满足应用程序的部署需要,在这种环境中是通过文件或剪贴板来实现数据共享的;而现在这个星球上的大部分计算机都联入了网络,因此在这些计算机上部署的软件不但必须要具有网络功能,还必须能够适应不断变化的网络环境。简而言之,软件开发早已不再是技术高手单枪匹马就能够完成任务的职业了,它已经变成了一种基于相当复杂的底层框架的集体行为了。

现在的程序员已经不能享受使用贴近处理器的底层工具(例如汇编或C编译器)来从头完成一个完整的软件工程的奢侈了。也很少有人有时间或耐心来编写中间层的框架了,即使是象HTTP协议的实现或者完成一个XML解析器这样简单的工作都很少有人来作,而具有调节底层框架来使系统达到所需的性能和质量的技能的人就更少了。现在软件开发最主要的重心放在了可重用代码和可重用组件上。操作系统加上少量的开发库这种方式已经不能满足软件开发的需要。因此,不管你喜不喜欢,今天的程序员都必须依赖多个不同来源的代码来支持他的应用程序,而且这些代码要能够正确可靠的协同工作。

为了适应当前软件开发模式的变化趋势,出现了一种新的软件开发方法学――基于组件的软件开发,它采用组合多个独立的代码模块的方式来创建应用程序。通过组合多个来源的组件,可以快速和高效的创建应用程序。然而,这门技术对编程工具和软件开发过程提出了新的需求。例如,因为依赖于其它由不被信任或不知名的开发者开发的组件,所以程序执行时的严格控制和在运行时对代码的验证成为软件正常运行最基本的要求。在我们这个遍布网路连接的时代,基于组件的复杂软件常常不需要客户端的操作就能动态更新,而有时这些更新可能是恶意的。如果询问那些计算机病毒的受害者保护她的机器和数据的干净是否必要,或者和一个不熟练的计算机使用者谈论那些他们所经历的,由于安装和卸载应用程序而导致系统莫名其妙的不稳定的情况,您就会发现基于组件的软件造成的问题几乎和它带来的好处一样之多。

多年来,对基于组件的软件开发的商业宣传和所预期的高效,被如何安全的将不同来源的组件组合起来工作的复杂性所抵消了。然而,最近10年中,我们看到了寄宿托管组件的虚拟执行环境在商业上的成功。托管组件是可以独立开发和部署的简单软件部件,不过它们可以在应用程序中安全的共存。托管组件的托管,是指它们需要一个虚拟执行环境来提供运行时和执行服务。为了满足组件的需要,这些环境着重致力于提供一个重点在于保证组件之间的安全合作和协作的结构良好的模型,而不只是简单的暴露它下层的处理器和操作系统的物理资源。

如图11所抽象描述的那样,虚拟执行环境和托管组件为三个不同的软件群体提供了很多好处:程序员,开发编程工具和编程库的人,以及那些管理在虚拟执行环境中运行的软件的管理员。对于那些使用托管组件开发复杂应用软件的程序员来说,开发工具和编程工具库的出现减少了花费在集成各组件和管理组件间通讯的任务上的时间,提高了生产率。对于工具软件开发者来说(例如编译器开发者),支持框架和一个清晰,说明详细的虚拟机的出现可以减少花费在框架和解决互操作性上的时间,而留出更多的时间来开发工具软件。(high-definition, carefully specified virtual machine??)最后,管理员和计算机用户可以从使用单一的运行时框架和打包模型中获益,并因此更好的控制计算机,所有这些都和特定的处理器和操作系统无关。

 

1-1     当寄宿在一个虚拟执行环境中时,各组件可以安全的进行协作。

 

CLI虚拟执行环境

       ECMA通用语言框架是一个虚拟执行环境的标准规范。它描述了一个数据驱动的架构,在其中,语言无关的数据块以自装配件,类型安全的软件系统的形式被激活。驱动这个过程的数据,叫做元数据,开发工具用它来描述软件的行为,以及软件在内存中运行的特性。CLI执行引擎利用元数据来达到将各个来源的组件安全装载到一起的目的。各CLI组件在严格控制和监督下共存,然而它们也能够互相访问,可以直接访问哪些需要共享的资源。CLI是一个良好的平衡了可控性和灵活性的模型。

       ECMA,欧洲计算机厂商联合会,是一个已有多年历史的标准化团体。除了发布它自己的标准之外,ECMA也和ISO(国际标准化组织)有着密切的关系,基于这种关系,CLI标准已经被认可为符合ISO/IEC 232712003标准,之后根据一篇科技报告,而成为ISOIEC 23272:2003标准,C#标准也被认可为符合ISO/IEC 232712003标准,并最终成为了ISO/IEC 23270:2003标准。

      

CLI标准可以在本书前言所提到的web站点中找到,它也包含在本书的随书光盘中。它由5大部分组成,外加上它的开发库的相关文档。在CLI被标准化的时候,一种名为C#的编程语言也由于共同的努力而被标准化了。C#利用了CLI的大部分特性,并且它是一种易学的面向对象语言,因此我们选择它来完成本书中的绝大部分例子小程序。在形式上,C#CLI标准是各自独立的(虽然C#标准确实引用了CLI标准),但实际上,这二者是纠缠在一起的,并且许多人认为C#是开发CLI组件的标准语言。

       CLI中的虚拟执行是在它的执行引擎的控制下发生的,执行引擎通过在运行时解释描述组件的元数据来寄宿组件,对于那些不是基于组件的代码也是一样。采用这种方式运行的代码常被称作托管代码,它们是使用可生成与CLI兼容的可执行程序的工具和编程语言来创建的。一个被详细说明的事件链被用来从称为装配件的包装工厂中装载元数据,并将元数据转化为适合在一个机器的处理器和操作系统上运行的可执行代码。图12演示了这个事件链的一个简化版本,它将成为本书其它部分的基础。CLI标准的第一部分也详细描述了这个事件链(标准第一部分中的第8节描述了通用类型系统,第11节描述了虚拟执行系统,这些都是非常好的背景资料)。

 

       12   CLI装载序列中的每一步都由前一阶段计算获得的元数据注释驱动,

 

       在某些方面,CLI执行引擎很象一个操作系统,因为它也是一段为在它的控制下执行的代码提供服务(例如装载,隔离和调度)和管理资源(例如内存和IO)的特权代码。还有,在CLI和操作系统中,服务都是即可以明确的被程序所请求,也可以作为执行模型环境的一部分而发挥作用。(环境服务是指在执行环境中持续运行的服务。它们非常重要,因为它们定义了一个系统的运行时计算模型的大部分内容)Ambient services????

       在其它方面,CLI很象传统的编译器,链接器和装载器的工具链,因为它也处理内存布局,编译和符号解析的工作。CLI标准不但极力详细描述了托管软件如何工作,还详细描述了非托管软件如何才能和托管软件安全的共存,以便能够无缝的共享计算资源和职责。CLI中系统和工具框架的结合使它成为创建基于组件的软件的唯一强有力的新技术。

 

CLI标准的基础概念

       CLI标准和执行模型的背后是一系列的核心思想。这些核心思想是以能够帮助开发者们组织和整理他们的代码的抽象或具体的技术的形式包含在CLI设计理念中的。让我们通过一系列的设计原则来思考这些技术。

l         使用统一的类型系统来暴露所有的可编程项。

l         将类型打包成完全自描述的可移植单元。

l         在运行时采用能够将各类型相互独立的方式装载类型,但是要能共享资源。

l         使用考虑了版本、特定文化的差异(例如日历或字符编码),以及管理策略的灵活的绑定机制解决运行时类型间的依赖问题。

l         采用能够校验类型安全的方式来描述类型的行为,但不要要求所有的程序都是类型安全的。

l         采用能够延迟到最后时刻的方式来处理针对特定处理器的任务,例如内存分配和编译。但也要考虑较早执行这些任务的工具。

l         在一个能够提供运行时策略的责任和执行的特权执行引擎的控制下执行代码。

l         将运行时服务设计成由可扩展的元数据格式来驱动,这样它们会容易适应新的情况和将来的变化。

在这里我们会谈到一些最重要的概念,然后在整本书的过程中再次详细的说明这些概念。

 

类型

       CLI将世界分为各种类型,程序员们也使用类型来组织他们编写的代码中的结构和行为。组件模型对类型的描述常常是非常简单的:一个类型描述了包含数据的字段和属性,还包含描述它的行为的方法和事件(所有这些都会在第3章中详细讨论)。状态和行为既可以在实例级别中存在(在这种形式中各个组件共享结构,但各个组件不相同),也可以在类型级别中存在(在这种形式中一个独立边界内的所有实例共享一个单一的数据拷贝或方法调度的信息)。最后,组件模型支持标准的面向对象结构,例如继承,基于接口的多态,以及构造器。

       对于执行引擎,程序员和其它类型来说,类型的结构采用元数据来表示,是很有用的。元数据之所以非常重要,是因为它使得来自于不同人员,地方和平台的类型能够和平的共存,并保持独立。缺省情况下,CLI只在需要用到某个类型时才会加载它;链接只有在需要的时候才会被求值,确定地址和编译。一个类型中所有对其它类型的引用都是符号,这就意味着它们是以名称的形式存在,在运行时再确定地址,而不是预先计算好地址和偏移量。通过使用符号引用,可以建立成熟的版本机制,各类型将来的独立版本可以在执行引擎的绑定逻辑中实现。

       使用经典面向对象的单继承语法,一个类型可以从另一个类型继承结构和行为。在子类的定义中会包含它的基类的所有方法和字段,一个子类的实例可以代替它的基类的实例。虽然类型可能只能有一个基类,但它们可以附加实现任意数目的接口。所有的类型都直接,或通过它们的父类的继承关系,间接的继承自基类型System.Object

       CLI组件模型向程序员暴露了两个更高级的结构:属性和事件,从而扩大了字段和方法的概念。属性允许类型暴露数据,数据的值可通过任意的代码来获取和设置,而不是通过直接的内存访问。从管道的角度来看,属性绝对是语法上的甜头,因为它们在内部表现为方法的形式,但是从语义学的角度来看,属性是一个类型的元数据最好的元素,能够导致更一致的API和更好的开发工具。

       类型使用事件在执行期间通知外部的观察者它们感兴趣的事件(例如,通知数据已经可用,或者内部状态的改变)。为了使外部观察者能够注册它们感兴趣的事件,CLI委托将执行一个回调所必需的信息包装起来。当注册一个事件回调时,程序员可以创建两种委托之一:一种是一个封装了指向类型的一个静态方法的指针的静态委托;另一种是一个将对象的引用和一个方法(对象会在这个方法上被回调)联系起来的实例委托。委托一般以参数的形式传递给事件注册方法;当类型需要触发一个事件时,它只是对那些在类型上注册的委托执行一下回调。

       类型使用字段来存储数据,使用方法来表示行为,从最低限度来说,它是一种采用上述方式来组织编程模块的分层方法。而在这之上,简洁性,完整性,模型,属性,事件,以及其它构造方式提供了附加的结构,可以使用这些结构来创建共享程序库和不同于CLI的运行时服务。

       COMCLI

       长期以来追求重用的软件设计者认为标准化的组件打包和运行时互操作性是最基础的。就像早期使用的穿孔打卡机就是计算函数的可重用的库所显示的那样。微软公司开发组件对象模型(COM)的原因是为了实现统一打包和细粒度的互操作性这两个目的。结果,使用“基于接口”的方法来进行二进制组件打包已经成功地被无数的软件开发者用来部署他们的API和将分散的代码模块化。与CLI不同,COM是一个几乎完全基于共享规则的组件模型,而不是一个共享的执行引擎。各COM组件共享底层的运行时基础结构,并在每一个组件的基础上进行功能协作。这个方法可以是非常有用的,尤其适合于那些计算机资源非常有限的环境,在这些环境中程序员必须压榨每一个字节的性能。或者是环境中存在数量巨大的代码需要暴露组件界面。

       只有在使用COM的共享规则后,组件之间的细粒度二进制互操作性才在Windows操作系统上的软件运行中普遍起来。它广泛而成功的作为一种方法来使用于应用程序为了提供可编程性而暴露内部,也用于发布API的标准方法。Windows的一些系统功能也通过COM接口来暴露,还有存在许多第三方厂商的控件是以可重用部件的方式来出售。

       然而,COM方法现在有明显的衰落趋势。在这个模型中,开发者要负责运行时操作的每一个细节,必须非常仔细的遵守复杂的互操作协议,以便组件能够正确的工作。因为使协议执行正确难度很大,所以代码不但繁杂,而且容易造成BUG

       大部分的COM复杂性都可以通过为组件开发者提供共享底层服务来消除,就像操作系统为所有使用计算机资源的程序提供共享底层服务一样(例如,内存垃圾回收,就是一种可以从根本上减少组件之间所必须进行的协作操作的服务)。1997年,人们提出了一种为COM服务的运行时,它能为COM编程者提供一个类模型,以及通用运行时服务,既能提高生产力(程序员不再需要重复的编写同样的支持机制),也能带来更好的安全性,高效率和稳定性。这个运行时最初的名称是组件对象运行时(COR),在共享源代码CLI的一些函数名称中还能找到这个名字。

       微软公司最初开发COR的目的只是希望能为COM提供一个运行时,但是微软公司没有局限与此,而是决定完成一个通用的虚拟执行环境。这个努力最终成为了CLI标准。

本文地址:http://com.8s8s.com/it/it43938.htm