第三讲 Microsoft.NET平台基础构造
抛开Microsoft.NET平台去谈C#是没有意义的,C#之“Sharp”也正在其后端强大的平台。仅仅拘泥于语法层面是体验不了C#的锐利之处的,C#程序很多诡秘之处必须依靠Microsoft.NET平台才能深度的掌握和运用。简单的讲,Microsoft.NET平台是一个建立在开放互联网络协议和标准之上,采用新的工具和服务来满足人们的计算和通信需求的革命性的新型XML Web智能计算服务平台。它允许应用程序在因特网上方便快捷地互相通信,而不必关心使用何种操作系统和编程语言。
从技术层面具体来说,Microsoft.NET平台主要包括两个内核,即通用语言运行时(Common Language Runtime,简称CLR)和Microsoft.NET框架类库,它们为Microsoft.NET平台的实现提供了底层技术支持。通用语言运行时是建立在操作系统最底层的服务,为Microsoft.NET平台的执行引擎。Microsoft.NET框架包括一套可被用于任何编程语言的类库,其目的是使得程序员更容易地建立基于网络的应用和服务。在此之上是许多应用程序模板,这些模板为开发网络应用和服务提供高级的组件和服务。Microsoft.NET平台之浩瀚绝非这里的几千字能够廓清,我们下面将着重体验那些对我们用C#开发应用程序至关重要的平台基础构造。
通用语言运行时(CLR)
通用语言运行时是整个Microsoft.NET框架赖以建构的基础,它为Microsoft.NET应用程序提供了一个托管的代码执行环境。它实际上是驻留在内存里的一段代理代码,负责应用程序在整个执行期间的代码管理工作,比较典型的有:内存管理,线程管理,安全管理,远程管理,即时编译,代码强制安全类型检查等。这些都可称得上Microsoft.NET框架的生命线。
实际上我们可以看出来,CLR代理了一部分传统操作系统的管理功能。在CLR下的代码称之为托管代码,否则称为非托管代码。我们也可将CLR看作一个技术规范,无论程序使用什么语言编写,只要能编译成微软中间语言 (MSIL),就可以在它的支持下运行,这使得应用程序得以独立于语言。目前支持CLR的编程语言多达二三十种。微软中间语言是我们在Microsoft.NET平台下编译器输出的PE文件的语言。它是Microsoft.NET平台最完整的语言集,非常类似于PC机上的汇编语言。即时编译器在运行时将中间语言编译成本地二进制代码。它为Microsoft.NET平台提供了多语言的底层技术支持。另外根据需要,Microsoft.NET即时编译器提供了特殊情况下的经济型即时编译和安装时编译技术。
CLR的设计目的便是直接在应用程序运行环境中为基于组件的编程提供第一等的支持。正如在Windows中添加了对窗口、控件、图形和菜单的直接支持,为基于消息的编程添加了底层结构,为支持设备无关性添加了抽象内容一样,CLR直接支持组件(包括属性和事件)、对象、继承性、多态性和接口。对属性和事件的直接支持使得基于组件的编程变得更简单,而不需要特殊的接口和适配设计模式。在组件运行时,CLR负责管理内存分配、启动和中止线程和进程、强化安全系数,同时还调整任何该组件涉及到的其他组件的附属配置。序列化支持允许以多种格式操作存储在磁盘上的组件,包括基于业界标准XML的SOAP。CLR提供了处理错误条件的有力、协调的方式。每个模块都具有内置的完整的元数据,这意味着诸如动态创建和方法调用之类的功能更容易,也更安全。映射甚至允许我们灵活地创建和执行代码。我们可以控制应用程序使用的组件的版本,这使应用程序更加可靠。组件代码是与处理器无关的和易于验证的中间语言 ( IL),而不是某一种特定的机器语言,这意味着组件不但可以在多种计算机上运行,而且可以确保组件不会覆盖它们不使用的内存,也不会潜在地导致系统崩溃。CLR根据托管组件的来源(例如来自因特网,企业局域网,本地机)等因素对他们判定以适当的信任度,这样CLR会根据他们的信任度来限定他们执行如读取文件,修改注册表等某些敏感操作的权限。借助通用类型系统(Common Type System,简称CTS)对代码类型进行严格的安全检查避免了不同组件之间可能存在的类型不匹配的问题。CLR下的编程全部是围绕组件进行的。
值得指出的是CLR通常寄宿在其他高性能的服务器应用程序中,比如:因特网信息服务器(IIS),Microsoft SQL Server。这使得我们可以充分利用通用语言运行时诸多的安全,高效的优点来部署自己的商业逻辑。
内存管理
CLR对程序员影响最大的就是它的内存管理功能,以至于我们很有必要单独把它列出来阐述。它为应用程序提供了高性能的垃圾收集环境。垃圾收集器自动追踪应用程序操作的对象,程序员再也用不着和复杂的内存管理打交道。这在某些喜欢张口闭口底层编程的所谓的高手来说,自动内存管理从来都是他们嘲笑的对象。的确,为通用软件环境设计的自动化内存管理器永远都抵不上自己为特定程序量身订制的手工制作。但现代软件业早已不再是几百行代码的作坊作业,动辄成千上万行的代码,大量的商业逻辑凸现的已不再是算法的灵巧,而是可管理性,可维护性的工程代码。.NET/C#不是为那样的作坊高手准备的,C语言才是他们的尤物。在Microsoft.NET托管环境下,CLR负责处理对象的内存布局,管理对象的引用,释放系统不再使用的内存(自动垃圾收集)。这从根本上解决了长期以来困扰软件的内存泄漏和无效内存引用问题,大大减轻了程序员的开发负担,提高了程序的健壮性。实际上我们在托管环境下根本找不到关于内存操作或释放的语言指令。值得指出的是Microsoft.NET应用程序可以使用托管数据,也可以使用非托管数据,但CLR并不能判断托管数据与非托管数据。
垃圾收集器负责管理.NET应用程序内存的分配和释放。当用new操作符创建新的对象时,垃圾收集器在托管堆(Managed Heap)中为对象分配内存资源。只要托管堆内的内存空间可用,垃圾收集器就为每一个新创建的对象分配内存。当应用程序不再持有某个对象的引用,垃圾收集器将会探测到并释放该对象。值得注意的是垃圾收集器并不是在对象引用无效时就立即开始释放工作,而是根据一定算法来决定什么时候进行收集和对什么对象进行收集。任何一个机器的内存资源总是有限的,当托管堆内的内存空间不够用时,垃圾收集器启动收集线程来释放系统内存。垃圾收集器根据对象的存活时间,对象历经的收集次数等来决定对哪些对象的内存进行释放。宏观的看,我们并不知道垃圾收集的确切行为,但Microsoft.NET类库为我们提供了控制垃圾收集行为的部分功能,在某些特殊情况下,我们有必要进行一些受限的操作。
垃圾收集器并不意味着程序员从此可以一劳永逸,如果正在操作一个包装了如文件,网络连接,Windows句柄,位图等底层操作系统资源的对象,我们还是需要明确地释放这些非托管资源的。这在“第五讲 构造器与析构器”里有详细的阐述。