四、对象的广泛应用
代码重用简化了开发过程,而可视化继承之类的功能又使得代码重用更加方便。然而,代码重用并不局限于此。借助作为VB.NET基础的CLR(Common Language Runtime,公共语言运行时环境),我们可以在VB.NET中继承其他VS.NET语言编写的类。例如我们可以编写一个C#类,然后在VB.NET类中继承该C#类。
VB.NET的面向对象功能已经向各个方向扩展,甚至深入到了语言本身——在VB.NET中,一切都是对象。它意味着和以前的VB版本相比,我们从VB.NET本身获得的支持和功能要多得多,求助于Windows API的时候将更少。例如,在以前的VB版本中,我们用LoadPicture方法装入一个图形,用Line方法(或者其他速度更快的API函数)画线;而在VB.NET中,我们用System.Drawing对象创建和处理图形。下面这段代码用System.Drawing对象在窗体上显示一个图形:
picshowpicture.Image = _
system.Drawing.Image.FromFile( _
"c:test.bmp")
注意,VB.NET的“一切都是对象”可能会使代码变得冗长。考虑下面这个语句,它在一个图形对象上面画一条黄绿色的线:
objgraphics.DrawLine(system.Drawing. _
Pens.Chartreuse, 0, 0, 100, 100)
语句虽然变长,但它获得的好处是:更加灵活,更加容易使用。以前,要实现一些较为复杂的功能往往要深入研究文档,通常还要求助于API。现在,所有相关的功能集都封装到了对象之中。用对象封装功能还有额外的优点——对象以一种极为优美的形式把相关功能组织了起来,所以浏览各个对象、看看它们到底做些什么,事实上也是一件有趣的事情。
Visual Basic.NET的面向对象特色带来了许多切实的好处。大多数情况下,和以前的VB版本相比,VB.NET面向对象的本性以及它对继承的支持使得创建某些类型的应用更加快速和方便。然而,虽然我们可以使用继承以及其他.NET的新功能,比如自由线程,但这些功能并不是一定得使用不可。正如所有其它语言的功能,我们必须使用的功能是那些对给定情形来说最具有意义的功能。
自由线程或许有必要特别说明。VB6允许通过单元线程创建多线程的服务,但VB从来没有支持过创建自由线程的客户程序。VB.NET改变了所有这一切。现在,创建自由线程的应用已经是一件非常平凡和普通的事情。它是如此平凡,以至于完全可以预料有些程序员在为应用加入自由线程时不会理解它的具体细节。启动新的线程只要很少的几行代码——只需把方法的地址传递给线程对象,该方法就会启动一个新的线程。这无疑极为实用和方便,但必须注意的是:这些功能只适合特定的情形,了解哪些情形适用这些功能以及如何恰到好处地运用这些功能属于开发者自己的责任。坦率地说,许多开发者会因为滥用继承和自由线程而给自己带来麻烦,希望这中间并不包括你。
五、公共运行时环境
迄今为止,业界对VB.NET讨论得最多的特色或许就是CLR。VB.NET运行在CLR之上,正是CLR为VB.NET带来了许多关键的新特色(包括缺点在内)。例如,CLR使得VB.NET支持跨语言的继承以及自由线程。
在VB6中,分布式VB程序要求有VB运行时库msvbvm60.dll支持,即该运行时库必须随同应用一起分发。其他许多语言,比如C++和Java,也有类似的要求。在.NET中,所有Visual Studio语言共享同样的运行时环境CLR。改用CLR带来了几个重要的结果:现在所有Visual Studio语言都共用同样的IDE、同样的窗体引擎、同样的异常处理机制,等等。它意味着Visual Basic在很大程度上已经可以和.NET的其他语言相提并论,如C#等。然而,对于CLR的异议仍旧存在,VB业界仍在激励地争辩它地价值。
不管应用是用VB、C#还是其他.NET语言编写,所有VS.NET代码都是编译成中间语言(Intermediate Language,IL)。当应用运行时,一个实时编译器(just-in-time compiler,或称为JIT)就把IL代码编译成机器语言。在理论上,它意味着为非Windows的平台构造.NET运行环境是可能的,但目前还没有出现有关这类系统的正式消息。IL有一个缺点:正如VB在5.0以前的版本,IL代码对于类似的反向编译工程很敏感。由于存在这种可能性,许多开发者对于.NET框架的整体安全性抱有怀疑。
对CLR进行优化影响IL层次上的代码,它使得所有使用CLR的语言受益。然而,对于特定语言的优化涉及到如何把代码编译成IL代码,它根据特定语言的语法进行。因此,.NET各种语言之间存在一定的性能差异是必然的。但不管如何,从整体上来看这仍旧是好事,例如CLR为VB带来了和C#一样的调试和分析工具——之所以能够如此,是因为它们都使用一样的工具。
CLR提供了前所未有的跨语言集成能力,其中包括跨语言继承代码的能力。所有使用CLR的语言都使用一个公共类型系统(Common Type System),它使得开发那些运用多种语言的应用变得更为容易。
在CLR之内运行的代码称为“受管理的代码”(Managed Code),受管理代码所使用的内存由CLR全面控制。受管理的代码有着许多优点,包括交叉语言集成、跨语言异常控制以及一个组件交互的简化模型。Visual Basic.NET只能以受管理代码方式运行,与此相对应,C#却具有将代码转入非受管理方式运行的能力(运行在CLR之外),比如执行指针处理之类的操作。这是VB.NET不能与C#相提并论的地方之一。然而,这种能力的是否重要,对于不同的人、不同的用途来说都有所不同。
由CLR导致的体系上的不同不仅仅是跨语言继承、共享功能和受管理代码,它还有更深刻的意义。Visual Studio.NET的底层体系不再是COM;另外,VB.NET中所有东西都是对象,甚至连字符串也一样。由于这些原因以及其他许多原因,Microsoft改变了底层体系管理对象的方法。COM系统通过引用计数方式管理对象,每当对象被引用时,引用计数就增加。当对象引用超出作用范围或者被释放时,计数器的值就减少;一旦引用计数为0,对象就被释放。Microsoft声称.NET体系中的引用计数开销实在太大,使得.NET采用引用计数不再合适,因此它就放弃了引用计数,改用垃圾回收(Garbage Collection)。
大约40年前,John McCarthy设计了LISP语言,它是可考证的第一种编程语言。LISP运行时不断地分配和释放大量的小块内存,由于那时的计算机内存远远没有现在这么庞大,因此早期的LISP用户很快感到内存不足,同时许多不再使用的内存却未能利用起来。为了解决这个问题,McCarthy于1959年第一次提出了垃圾回收的思想。
在一个真正面向对象的系统中,垃圾回收机制能够很好地满足分配和释放大量小块内存的需要。因此,Microsoft在VS.NET中重新实现了垃圾回收机制。
CLR垃圾回收器(CLR Garbage Collector)的主要任务就是监视程序使用的资源,当可用资源达到某个确定的极限时查找不再使用的对象,如发现有这类对象存在则释放它们所占用的资源。垃圾回收的一个很大的优点是程序员无需再为大多数常见的循环引用担心。在循环引用情形下,子对象拥有对父对象的引用,同时父对象又拥有对子对象的引用。在引用计数模式下,循环引用阻止了系统释放和拆除任意一个对象。然而,垃圾回收器能够找出这类循环引用并拆除它们。垃圾回收机制同时也意味着,当对象的最后一个引用被释放时,对象并不一定立即被拆除。
采用垃圾回收机制的一个后果是:我们不能再希望类的Terminate事件总是适时触发。事实上,如果线程被阻塞的话,Terminate事件可能完全不会触发。这就是所谓的“非确定的结束”(non-deterministic finalization),而COM提供的则是“确定的结束”。由于缺乏“确定的结束”,再加上因为垃圾回收器重新组织和整理内存导致不能运用指针,新闻组中出现了对该问题激烈的争论:有些人憎恨这些新的限制,因为他们依赖于“确定的结束”;有些人觉得无关紧要,因为他们并不依赖于Terminate事件。
从引用计数转变到垃圾回收仅仅是Visual Studio.NET底层体系不再是COM这一变化的诸多必然结果之一。虽然VB.NET之内仍旧可以使用COM对象,但这些对象必须通过封装(Wrapper)才能访问。任何时候,封装都意味着性能的降低,甚至还有可能导致对象行为的异常。如果要迁移一个大量使用COM对象的工程,你必须认真地进行计划和测试,应用程序的某些部分可能还需要重新构造。
七、面向Web的支持
除了Windows Forms新引擎之外,.NET还包含了一个专门为构造Web窗体设计的窗体引擎,称为Web Forms。这个引擎的目标在于让用户能够象创建传统Windows桌面应用的窗体一样方便地创建Web窗体。Web Forms是一种ASP.NET技术,通过它我们可以使用熟悉的RAD(快速程序开发)工具构造出带有执行代码的窗体。不过,窗体中的ASP.NET代码以编译方式在服务器端运行,经过处理后把结果HTML发送给支持HTML 3.2的浏览器。
客户端事件数据由底层框架截获并发送到服务器。这意味着应用界面不再受浏览器类型的约束,意味着有大量UI工具可供使用,意味着用户可以充分发挥现有的窗体制作技巧。如果应用没有必要做到浏览器中立,那么它就可以利用IE浏览器的各种特色。有了Web Forms,我们将能够更轻松地为那些具有Web功能的应用构造出更好、更丰富的用户界面。
VB.NET中另外一个面向Web的重要特色是Web服务。在Microsoft的宣传中,Web服务被推崇为之所以要采用.NET技术的重要理由之一。事实上,从根本上来说Web服务是一种类似COM的、通过Web服务器和标准协议发布的对象。当然,Web服务并不是严格意义上的COM对象,但两者作用方式类似。Microsoft期待着各类公司都以Web服务方式提供服务,期待着未来创建应用时只需简单地“粘合”各种服务,就象今天借助Office和支持VBA的应用通过VBA构造新应用一样简单快捷。
从Microsoft PDC(Professional Developers Conference,专业开发者大会)的一个演示中,我们可以看出Microsoft希望开发者如何粘合各种Web服务。在这个演示中,一个假想的医生以Web服务形式发布其时间表,示范如何通过Web用智能电话和医生订立约会。Visual Basic.NET还允许查询服务器,提取服务器支持的所有服务的元数据。Web服务描绘了Microsoft野心勃勃的战略,然而,唯有时间才能告诉我们Microsoft是否在大范围推广Web服务上取得了成功。但不管如何,这个想法本身看来有着美好的前途。
为了减少与封装和分发应用有关的问题,如令人畏惧的DLL Hell问题(在共享DLL的应用之间,由于一个应用的升级而导致另一个应用无法正常运行的情况),Microsoft作出了种种努力,它同样也带来了美好的希望。所有.NET应用都封装为程序集(Assembly)。程序集包含了描述各种运行需求的元数据。这种元数据称为manifest,其中包括:程序集的标识信息(名称,版本等),列出了所有文件依赖关系以及文件位置和文件版本的文件清单,外部依赖信息(带有描述程序集必须用到、但开发者没有自己创建的DLL以及其他资源的数据)。程序集是通过manifest自我描述的,因此.NET应用的运行并不需要修改注册表。换句话说,.NET应用不再要求注册组件。在最理想的情况下,客户机器上已经有了.NET运行环境,部署一个复杂的应用简单到只需复制一个文件夹到目标机器。使用程序集的另外一个优点是:不同的应用可以拥有同一DLL的不同版本,所有这些应用都互不干涉地在同一台机器上运行。如果它能够按照预期那样获得成功,DLL Hell和可怕的版本问题都将成为历史。
Visual Basic.NET代表着VB的一次重大飞跃。尽管如此,把VB.NET看成是一种有着熟悉语法的新语言而不是对旧语言的简单升级或许是对待VB.NET较为正确的心态。