分享

Beginning C# 2008读书笔记系列―― 介绍C# - 思索、坚韧、创新、成长 ...

 北海藏经阁 2010-06-12

Beginning C# 2008读书笔记系列―― 介绍C#

这是本书的第一章将提供要掌握C#所需的基本知识。本章将提供C#和.NET Framework的视图,包括C#和.NET Framework技术,使用它们的动机,以及它们之间怎样彼此联系。

.NET Framework技术包含的许多概念从一开始就紧密的结合在一起。这意味着这里讨论的.NET Framework将按照必要性简要地介绍一些新概念。然而,快速着眼于基础是理解怎样用C#编程的本质。

在概述性的介绍之后,本章将提供C#语言自身比较简单的介绍,包括C#起源于并类似C++。

1.1 什么是.NET Framework?

.NET Framework是Microsoft为发展中的应用程序而设计开发的新的、革命性的平台。有许多关于这个论述是多么含糊不清的趣事――但这是有很多原因的。首先,注意.NET Framework不仅仅是"在Windows操作系统上开发应用程序。"虽然Microsoft发行的.NET Framework运行在Windows操作系统,工作在其他操作系统上的替代版本将很快成为可能。Mono就是个例子,Mono是一个运行在多个操作系统的.NET Framework开源版本,包括不同风味的Linux和Mac操作系统。另外,可以在个人数字助理(PDA)类型的设备,甚至一些智能电话上使用微软.NET Framework(本质上是完整.NET Framework的子集)。一个使用.NET Framework关键的动机是.NET Framework底层是有意作为汇聚多种根本不同的操作系统而使用的。(即基于.NET Framework的应用程序是可以在多个完全不同的操作系统上运行的。)

另外,先前定义的.NET Framework包括了对应用程序的类型没有限制是合理的。这是因为它们是不受限制的――.NET Framework允许创建Windows程序、Web应用程序、Web服务,以及其他相当多你能想到的任何事。

.NET Framework是为任何语言而设计的,因此任何语言都能使用它;其中包括C#、C++、Visual Basic、Jscript和一些更老的语言诸如COBOL。为了这个目的,这些针对语言的特定版本.NET Framework也出现了,并且更多版本将始终发行。它们不仅访问.NET Framework而且能彼此通信。C#开发人员调用由Visual Basic开发人员编写的代码这是完全可能的,反之亦然。

所以这些都是为可用性提供难以想象的水平而准备的,而可用性是怎样使用.NET Framework的一部分,诸如诱人的前景。

.NET Framework是什么?

.NET Framework主要有巨大的代码库构成,该代码库可以通过客户端语言(诸如C#)使用面向对象(OOP)技术访问。该代码库被分类为不同的模块――可以根据你想要实现的目的而使用相应的部分。例如,包含构建Windows应用程序的模块,包含构建网络编程的模块,包含构建Web开发的模块等等。许多模块被分解为更多的特定子模块,诸如构建Web服务的模块是构建Web开发的一个内部模块。

由于不同操作系统的目的不同,因此这些操作系统支持部分的或全部的模块,取决于它们的特性。例如,PDA支持.NET核心部分,但不太可能需要一些更深奥的模块。

部分.NET Framework定义了一些基本类型。类型是数据的一种表现形式,指定其中一些最基础的部分(诸如32位有符号整数),以便使用.NET Framework在不同语言之间提供交互操作。这称为通用类型系统(CTS)。

除了支持这个库之外,.NET Framework还包含.NET Framework通用语言运行库(CLS),主要负责维护所有使用.NET库开发的应用程序的运行。

【MSDN】

.NET Framework 具有两个主要组件:公共语言运行库和 .NET Framework 类库。公共语言运行库是 .NET Framework 的基础。您可以将运行库看作一个在执行时管理代码的代理,它提供内存管理、线程管理和远程处理等核心服务,并且还强制实施严格的类型安全以及可提高安全性和可靠性的其他形式的代码准确性。事实上,代码管理的概念是运行库的基本原则。以运行库为目标的代码称为托管代码,而不以运行库为目标的代码称为非托管代码。.NET Framework 的另一个主要组件是类库,它是一个综合性的面向对象的可重用类型集合,您可以使用它开发多种应用程序,这些应用程序包括传统的命令行或图形用户界面 (GUI) 应用程序,也包括基于 ASP.NET 所提供的最新创新的应用程序(如 Web 窗体和 XML Web Services)。

.NET Framework 可由非托管组件承载,这些组件将公共语言运行库加载到它们的进程中并启动托管代码的执行,从而创建一个可以同时利用托管和非托管功能的软件环境。.NET Framework 不但提供若干个运行库宿主,而且还支持第三方运行库宿主的开发。

例如,ASP.NET 承载运行库以为托管代码提供可伸缩的服务器端环境。ASP.NET 直接使用运行库以启用 ASP.NET 应用程序和 XML Web Services。

Internet Explorer 是承载运行库(以 MIME 类型扩展的形式)的非托管应用程序的一个示例。使用 Internet Explorer 承载运行库使您能够在 HTML 文档中嵌入托管组件或 Windows 窗体控件。以这种方式承载运行库使得托管移动代码(类似于 Microsoft® ActiveX® 控件)成为可能,不过它需要进行重大改进(如不完全受信任的执行和独立的文件存储),而这种改进只有托管代码才能提供。

下面的插图显示公共语言运行库和类库与应用程序之间以及与整个系统之间的关系。该插图还显示托管代码如何在更大的结构内运行。

.NET Framework 环境


 

.NET Framework 类库

.NET Framework 类库是一个与公共语言运行库紧密集成的可重用的类型集合。该类库是面向对象的,并提供您自己的托管代码可从中导出功能的类型。这不但使 .NET Framework 类型易于使用,而且还减少了学习 .NET Framework 的新功能所需要的时间。此外,第三方组件可与 .NET Framework 中的类无缝集成。

例如,.NET Framework 集合类实现一组可用于开发您自己的集合类的接口。您的集合类将与 .NET Framework 中的类无缝地混合。

 

公共语言运行库的功能

公共语言运行库管理内存、线程执行、代码执行、代码安全验证、编译以及其他系统服务。这些功能是在公共语言运行库上运行的托管代码所固有的。

至于安全性,取决于包括托管组件的来源(如 Internet、企业网络或本地计算机)在内的一些因素,托管组件被赋予不同程度的信任。这意味着即使用在同一活动应用程序中,托管组件既可能能够执行文件访问操作、注册表访问操作或其他须小心使用的功能,也可能不能够执行这些功能。

运行库强制实施代码访问安全。例如,用户可以相信嵌入在网页中的可执行文件能够在屏幕上播放动画或唱歌,但不能访问他们的个人数据、文件系统或网络。这样,运行库的安全性功能就使通过 Internet 部署的合法软件能够具有特别丰富的功能。

运行库还通过实现称为通用类型系统 (CTS) 的严格类型验证和代码验证基础结构来加强代码可靠性。CTS 确保所有托管代码都是可以自我描述的。各种 Microsoft 和第三方语言编译器生成符合 CTS 的托管代码。这意味着托管代码可在严格实施类型保真和类型安全的同时使用其他托管类型和实例。

此外,运行库的托管环境还消除了许多常见的软件问题。例如,运行库自动处理对象布局并管理对对象的引用,在不再使用它们时将它们释放。这种自动内存管理解决了两个最常见的应用程序错误:内存泄漏和无效内存引用。

运行库还提高了开发人员的工作效率。例如,程序员可以用他们选择的开发语言编写应用程序,却仍能充分利用其他开发人员用其他语言编写的运行库、类库和组件。任何选择以运行库为目标的编译器供应商都可以这样做。以 .NET Framework 为目标的语言编译器使得用该语言编写的现有代码可以使用 .NET Framework 的功能,这大大减轻了现有应用程序的迁移过程的工作负担。

尽管运行库是为未来的软件设计的,但是它也支持现在和以前的软件。托管和非托管代码之间的互操作性使开发人员能够继续使用所需的 COM 组件和 DLL。

运行库旨在增强性能。尽管公共语言运行库提供许多标准运行库服务,但是它从不解释托管代码。一种称为实时 (JIT) 编译的功能使所有托管代码能够以它在其上执行的系统的本机语言运行。同时,内存管理器排除了出现零碎内存的可能性,并增大了内存引用区域以进一步提高性能。

最后,运行库可由高性能的服务器端应用程序(如 Microsoft® SQL Server™ 和 Internet 信息服务 (IIS))承载。此基础结构使您在享受支持运行库宿主的行业最佳企业服务器的优越性能的同时,能够使用托管代码编写业务逻辑。

使用基于公共语言运行库的语言编译器开发的代码称为托管代码;托管代码具有许多优点,例如:跨语言集成、跨语言异常处理、增强的安全性、版本控制和部署支持、简化的组件交互模型、调试和分析服务等。

若要使公共语言运行库能够向托管代码提供服务,语言编译器必须生成一些元数据来描述代码中的类型、成员和引用。元数据与代码一起存储;每个可加载的公共语言运行库可移植执行 (PE) 文件都包含元数据。公共语言运行库使用元数据来完成以下任务:查找和加载类,在内存中安排实例,解析方法调用,生成本机代码,强制安全性,以及设置运行时上下文边界

公共语言运行库自动处理对象布局并管理对象引用,当不再使用对象时释放它们。按这种方式实现生存期管理的对象称为托管数据。垃圾回收消除了内存泄漏以及其他一些常见的编程错误。如果您编写的代码是托管代码,则可以在 .NET Framework 应用程序中使用托管数据、非托管数据或者同时使用这两种数据。由于语言编译器会提供自己的类型(如基元类型),因此您可能并不总是知道(或需要知道)这些数据是否是托管的。

有了公共语言运行库,就可以很容易地设计出能够跨语言交互的组件和应用程序。也就是说,用不同语言编写的对象可以互相通信,并且它们的行为可以紧密集成。例如,可以定义一个类,然后使用不同的语言从原始类派生出另一个类或调用原始类的方法。还可以将一个类的实例传递到用不同的语言编写的另一个类的方法。这种跨语言集成之所以成为可能,是因为基于公共语言运行库的语言编译器和工具使用由公共语言运行库定义的通用类型系统,而且它们遵循公共语言运行库关于定义新类型以及创建、使用、保持和绑定到类型的规则。

所有托管组件都带有生成它们所基于的组件和资源的信息,这些信息构成了元数据的一部分。公共语言运行库使用这些信息确保组件或应用程序具有它需要的所有内容的指定版本,这样就使代码不太可能由于某些未满足的依赖项而发生中断。注册信息和状态数据不再保存在注册表中(因为在注册表中建立和维护这些信息很困难)。取而代之的是,有关您定义的类型(及其依赖项)的信息作为元数据与代码存储在一起,这样大大降低了组件复制和移除任务的复杂性。

通用类型系统定义了如何在运行库中声明、使用和管理类型,同时也是运行库支持跨语言集成的一个重要组成部分。通用类型系统执行以下功能:

  • 建立一个支持跨语言集成、类型安全和高性能代码执行的框架。
  • 提供一个支持完整实现多种编程语言的面向对象的模型。
  • 定义各语言必须遵守的规则,有助于确保用不同语言编写的对象能够交互作用。

 

 

使用.NET Framework编写应用程序

使用.NET Framework编写应用程序意味着使用.NET Framework代码库编写代码(使用任何.NET Framework支持的语言)。本书使用VS和VCE作为开发环境。这些环境的优点是能更好地将.NET的特征融入到代码中。可以完全使用C#编写代码,但使用.NET Framework整个过程中,能根据需要使用VS和VCE的其他工具。

为了执行C#代码,必须把它们转换为目标操作系统所能理解的语言,即本地代码;这种转换称为编译代码,由编译器执行。然而在.NET Framework环境下,这个过程分为两个阶段。

MSIL和JIT

当编译使用.NET Framework库的代码时,不是立即创建操作系统特定的本地代码,而是将代码编译为微软中间语言(Microsoft Intermediate Language,MSIL)代码。这个代码不专用于任何一种操作系统,也不专用于C#语言的。其他.NET语言,诸如Visual Basic.NET也在第一阶段编译成MSIL代码。

显然,运行一个程序必须完成更多的工作,这就是即时编译器(Just-in-Time,JIT),JIT编译器将MSIL代码编译为特定的OS和目标机器体系结构的本地代码。只有完成这个步骤,操作系统才能运行程序。编译器的名称Just-in-Time,反映MSIL代码仅在需要时才编译这个事实。

在过去,编译器常常把代码编译成几个程序,每个程序都以特定的操作系统和CPU结构体系为目标。常常,这是一种优化形式(例如,为了代码在AMD的CPU运行更快些),有时这是重要的(例如对于工作在Win9x和WinNT/2000环境的程序),现在就不必要了。因为JIT编译器使用MSIL代码,而MSIL代码是与机器、操作系统和CPU无关的。存在不同的JIT编译器,每个编译器都针对不同的体系结构,根据需要总能找到一个合适的编译器创建的本地代码。

【MSDN】

托管执行过程包括下列步骤:

  1. 选择编译器。

    为获得公共语言运行库提供的优点,必须使用一个或多个针对运行库的语言编译器。

  2. 将代码编译为 Microsoft 中间语言 (MSIL)。

    编译将源代码翻译为 MSIL 并生成所需的元数据。

  3. 将 MSIL 编译为本机代码。

    在执行时,实时 (JIT) 编译器将 MSIL 翻译为本机代码。在此编译过程中,代码必须通过验证过程,该过程检查 MSIL 和元数据以查看是否可以将代码确定为类型安全。

  4. 运行代码。

    公共语言运行库提供使执行能够发生以及可在执行期间使用的各种服务的结构。

编译为 MSIL

当编译为托管代码时,编译器将源代码翻译为 Microsoft 中间语言 (MSIL),这是一组可以有效地转换为本机代码且独立于 CPU 的指令。MSIL 包括用于加载、存储和初始化对象以及对对象调用方法的指令,还包括用于算术和逻辑运算、控制流、直接内存访问、异常处理和其他操作的指令。要使代码可运行,必须先将 MSIL 转换为特定于 CPU 的代码,这通常是通过实时 (JIT) 编译器来完成的。由于公共语言运行库为它支持的每种计算机结构都提供了一种或多种 JIT 编译器,因此同一组 MSIL 可以在所支持的任何结构上 JIT 编译和运行。

当编译器产生 MSIL 时,它也产生元数据。元数据描述代码中的类型,包括每种类型的定义、每种类型的成员的签名、代码引用的成员和运行库在执行时使用的其他数据。MSIL 和元数据包含在一个可移植可执行 (PE) 文件中,此文件基于并扩展过去用于可执行内容的已公布的 Microsoft PE 和公共对象文件格式 (COFF)。这种文件格式包含 MSIL 或本机代码以及元数据,使得操作系统能够识别公共语言运行库映像。文件中的元数据以及 MSIL 的存在使代码能够描述自身,这意味着不再需要类型库或接口定义语言 (IDL)。运行库在执行过程中根据需要从该文件中查找并提取元数据。

运行代码

公共语言运行库提供了使托管执行能够发生并提供可以在执行期间使用的各种服务的结构。在运行方法之前,必须先将其编译为特定于处理器的代码。当首次调用已经为其生成 Microsoft 中间语言 (MSIL) 的每个方法,然后运行该方法时,该方法将是实时编译的(JIT 编译)。下次运行该方法时,将运行现有的 JIT 编译的本机代码。这种进行 JIT 编译然后执行代码的过程一直重复到执行完成时为止。

在执行过程中,托管代码接收若干服务,这些服务涉及垃圾回收,安全性,与非托管代码的互操作性,跨语言调试支持,增强的部署,以及版本控制支持等。

在 Microsoft Windows XP 和 Windows Vista 中,操作系统加载程序通过检查通用对象文件格式 (COFF) 头中的某个位来检查托管模块。所设置的位表示托管模块。如果加载程序检测到托管模块,它将加载 mscoree.dll。_CorValidateImage 和 _CorImageUnloading 将分别在加载和卸载托管模块时通知加载程序。_CorValidateImage 执行下列操作:

  1. 确保代码是有效的托管代码。
  2. 将映像中的入口点更改为运行库中的入口点。

在 64 位的 Windows 上,_CorValidateImage 会修改内存中的映像,将其从 PE32 格式转换为 PE32+ 格式。

 

 

程序集

当编译程序时,创建MSIL代码并存储在程序集中。程序集包括可执行的应用程序文件(这些文件能直接在Windows上运行,不需要其他任何程序,其扩展名是.exe)和被其他应用程序使用的库(其扩展名是.dll)。

除了包含MSIL外程序集还包括元信息(即程序集中包含的数据信息,也称为元数据)和可选的资源(被MSIL额外使用的数据,诸如声音文件和图片)。元信息允许程序集完全是自描述的。不需要其他信息就能使用程序集,意味着可以避免下列情形,诸如不能把需要的数据添加到系统注册表等等,而这种情形在采用其他平台开发时,这是经常发生的。

这意味着部署应用程序常常像把一个文件复制到远程计算机上的目录一样简单。因为没有目标系统需要的附加信息,可以在目录中直接运行这个程序(假设已安装.NET CLR)。

当然没有必要把运行一个程序所需的信息都安装到同一个地方。可以写一些代码执行多个应用程序所需的任务。基于这种情形,把可重用代码存放在所有程序都能访问到的地方是很有用的。在.NET Framework中,这个地方称为全局程序集高速缓存(GAC)。将代码存放在GAC中是简单的,只需将程序集包含的代码存放在包含高速缓存的目录下即可。

 

【MSDN】

程序集是 .NET Framework 编程的基本组成部分。程序集执行以下功能:

  • 包含公共语言运行库执行的代码。如果可移植可执行 (PE) 文件没有相关联的程序集清单,则将不执行该文件中的 Microsoft 中间语言 (MSIL) 代码。请注意,每个程序集只能有一个入口点(即 DllMain、WinMain 或 Main)。
  • 程序集形成安全边界。程序集就是在其中请求和授予权限的单元。
  • 程序集形成类型边界。每一类型的标识均包括该类型所驻留的程序集的名称。在一个程序集范围内加载的 MyType 类型不同于在其他程序集范围内加载的 MyType 类型。
  • 程序集形成引用范围边界。程序集的清单包含用于解析类型和满足资源请求的程序集元数据。它指定在该程序集之外公开的类型和资源。该清单还枚举它所依赖的其他程序集。
  • 程序集形成版本边界。程序集是公共语言运行库中最小的可版本化单元,同一程序集中的所有类型和资源均会被版本化为一个单元。程序集的清单描述您为任何依赖项程序集所指定的版本依赖性。
  • 程序集形成部署单元。当一个应用程序启动时,只有该应用程序最初调用的程序集必须存在。其他程序集(例如本地化资源和包含实用工具类的程序集)可以按需检索。这就使应用程序在第一次下载时保持精简。
  • 程序集是支持并行执行的单元。

程序集可以是静态的或动态的。静态程序集可以包括 .NET Framework 类型(接口和类),以及该程序集的资源(位图、JPEG 文件、资源文件等)。静态程序集存储在磁盘上的可移植可执行 (PE) 文件中。您还可以使用 .NET Framework 来创建动态程序集,动态程序集直接从内存运行并且在执行前不存储到磁盘上。您可以在执行动态程序集后将它们保存在磁盘上。

有几种创建程序集的方法。您可以使用过去用来创建 .dll 或 .exe 文件的开发工具,例如 Visual Studio 2005。您可以使用 Windows 软件开发工具包 (SDK) 中提供的工具来创建带有在其他开发环境中创建的模块的程序集。您还可以使用公共语言运行库 API(例如 Reflection.Emit)来创建动态程序集。

 

托管代码

当把代码编译成MSIL,并利用JIT编译器将MSIL代码编译成本地代码之后,CLR并没有结束。当使用.NET Framework编写的代码在执行时(这个阶段通常称为运行时)是被托管的。这意味着CLR负责管理程序,其方式是管理内存、处理安全、允许跨语言调试等等。反之,应用程序没有在CLR控制下运行称为非托管,某些语言诸如C++能编写这样的应用程序,例如访问操作系统底层的功能。然而,在C#中只能编写在托管环境下运行的代码。我们将使用CLR提供的托管功能,并且由.NET自己处理与操作系统之间的交互。

垃圾回收

托管代码最重用的一个功能是垃圾回收。这种.NET方法确保应用程序不再使用某些内存时,这些内存就会完全被释放。在.NET推出之前,这是程序员的职责。代码中少量的简单错误会将大的内存块分配到错误的地方,导致这些内存神秘消失。这通常意味着计算机运行速度逐渐减慢而最终系统崩溃。

.NET垃圾回收频繁检测计算机内存,回收长时间未使用的内存空间。这是没有设置时间帧,它可以在一秒中检测几千次,也可以几秒钟才检测一次或者任意时刻检测,但可以肯定进行了检查。

这里要给程序员一些提示。因为这项工作是在不可预知的情况下进行的,因此程序设计时应该考虑这一点。需要很多的内存才能运行的程序应该能自己检查,而不是坐等垃圾回收,但听起来并不是很难的。

 

【MSDN】

垃圾回收

.NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次您使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。但是,内存不是无限大的。最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。

 

组合在一起

在继续学习之前,先把前面介绍的创建一个.NET Framework应用程序所需的步骤总结一下:

  1. 应用程序采用与.NET兼容的语言(如C#)编写代码。

  2. 代码编译成MSIL,并存储在程序集中。

  1. 当代码执行时(如果它是一个可执行文件则自动运行,或者当其他代码调用它时运行),代码必须首先使用JIT编译器编译为本机代码。

  2. 在托管的CLR环境中运行本机代码和其他任意的应用程序或进程。

 

链接

在上述过程中还要注意一点。在第二步骤中编译成MSIL时C#代码不一定被合并到一个文件中,可以把应用程序代码分割成多个源代码文件,再把它们编译到一个程序集中。这个非常有用的过程成为链接。这是因为处理几个文件比处理一个巨大的文件简单得多。可以将逻辑上相关的代码分离到一个单独的文件,因此能单独处理,也更容易在需要时找到它们,让团队的开发人员将程序工作分解为易管理的模块,借此每个人可以单独编写一个代码块,而不会冒着破坏其他已完成的部分或其他人正在处理的部分的危险。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多