C#本质论(中文版)

所需积分/C币:10 2011-12-25 19:01:50 5MB PDF
1
收藏 收藏
举报

C#本质论(中文版) C#本质论
互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第章 体系结构 Microsoft认为这个过程要比一开始就编译整个应用程序代码的效率髙得多,因为任何应用 程序的大部分代码实际上并不是在每次运行过程中都执行。使用JIT编译器,从来都不会 编译这种代码。 这解释了为什么托管Ⅱ代码的执行儿乎和内部机器代码的执行速度一样快,但是并没 有说明为什么 Microsoft认为这会提高性能。其原因是编译过程的最后一部分是在运行时进 行的,JI编译器确切地知道程序运行在什么类型的处理器上,可以利用该处理器提供的 任何特性或特定的机器代码指令来优化最后的可执行代码。 传统的编译器会优化代码,但它们的优化过程是独立于代码所运行的特定处理器的 这是因为传统的编译器是在发布软件之前编译为内部机器可执行的代码。即编译器不知道 代码所运行的处理器类型,例如该处理器是x86兼容处理器还是Apha处理器,这超出了 基本操作的范围。例如Ⅴ isual studio6为一般的奔腾机器进行了优化,所以它生成的代码 不能利用奔腾Ⅲ处理器的使件特性。相反,JI编译器不仅可以进行Ⅴ isual studio6所 能完成的优化工作,还可以优化代码所运行的特定处理器。 语言的互操作性 使用LL不仅支持平台无关性,还支持语言的互操作性。简而言之,就是能将任何一种 语言编译为中间代码,编译奷的代码可以与从其他语言编译过来的代码进行交操作 那么除了C#之外,还有什么语言可以通过NFT进行交互操作呢?下面就简要讨论其 他常见语言如何与NET交互操作。 Visual basic6在升级到 isual basic.NET2002时,经历了一番脱胎换骨的变化,才集 成到 NET Framework的第一版中。 Visual basic语言对Ⅴ isual basic6进行了很大的演化, 也就是说,Ⅴ isual basic6并不适合运行NET程序。例如,它与COM的高度集成,且只把 事件处哩程序作为源代码显示给丌发人员,大多数后台代码不能用作源代码。另外,它不 支持继承,ⅵ isual basic使用的标准数据类型也与.NET不兼容。 Visual basic6在2002年升级为Ⅴ isual Basic Net,对 Visual basic进行的改变非常大, 完全可以把 Visual basic当作是一种新语言。现有的Ⅴ isual basic6代码不能编译为Ⅴ Visual Basic2005代码(或Ⅵ Visual basic net2002和2003代码),把Ⅴ isual basic6程序转换为Ⅴisua Basic2005时,需要对代码进行大量的改动,但大多数修改工作都可以由 Visual studio 2005( Visual studio的升级版本,用于与NET一起使用)自动完成。如果把Ⅴ Visual basic6项 目读到Ⅴ Visual studio2005中,Ⅴ isual studio2005就会升级该项目,也就是说把 isual basic 6溟代码重写为Ⅴ isual basic205溟代码。虽然这意味着其中的⊥作已大大减轻,但用户 仍需要检査新的ⅵ isual basic2005代码,以确保项目仍可正确工作,因为这种转换并不十 分完关。 这种语言升级的一个作用是不能再把 Visual basic2005编译为内部可执行代码了。 Visual basic2005只编译为中间语言,就像〔#一样。如果需要继续使用 Visual basic6编写 程序,就可以这么做,但生成的可执行代码会完全忽咯 NET Framework,如果继续把Ⅴ isual Studio作为开发环境,就需要安装Ⅴ isual studio6。 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第Ⅰ部分语言 Visual o+6有许多 Microsoft对 Windows的特定扩展。通过Ⅴ isual c++.NET,又加 入了更多的扩展内容,来支持 NET Framework。现有的CH源代码会继续编译为内部可执 行代码,不会有修改,但它会独立」NET运行库运行。如果让C++代码在 NeT Framework 中运行,就可以在代码的开头添加下述命令 还可以把标记/(lr传递给编译器,这样编译器假定要编译托管代码,因此会生成中间 语言,而不是内部机器码。C++的一个有趣的问题是在编译托管代码时,编译器可以生成 包含内嵌本机可执行代码的IL。这表小在C艹+代码中可以把托管类型和非托管类型合并起 来,因此托管C+代码 定义了一个普通的CH类,而代码 生成了一个托管类,就好像使用C或Ⅴ isual basic2005编写类一样。实际上,托管 C++比C#更优越的一点是可以在托管C++代码中调用非托管C←类,而不必采用COM交 互功能。 如果在托管类型上试图使用NE不支持的特性(例如,模板或类的多继承),编译器就 会出现一个错误。另外,在使用托管类时,还需要使用非标准的C艹+特性(例如上述代码中 的gc关键字) 因为C++允许低缬指针操作,C++编译器不能生成可以通过CLR内存类型安全测试的 代码。如果CLR把代码标识为内存类型安仝是非常重要的,就需要用其他一些语言编写源 代码,例如C#或 Visual basic2005。 最新添加的语言是Ⅴisua#2005。在 NET Framework1.1版本推出之前,用户必须下 载相应的软件,才能使用JH。现在J语言内置」 NeT Framework中。因此,J用户可以利 用ⅵ isual studio2005的所有常见特性。 Microsof希望人多数J++用户认为他们在使用NET 时,将很容易使用J。]不使用Java运行库,而是使用与其他NET兼容语言一样的基类 库。这说明,与C#和 isual basic2005一样,可以使用J#创建 ASP. NET Web应用程序、 Windows窗体、 XML Wcb服务和其他应用程序。 脚本语言 脚本语言仍在使用之中,但由于NET的推出,它们的重要性在降低。与此同时, JScript 升级到了 JScript. NET。现在 ASPNEt页面可以用 JScript. NET编写,可以把 JScript. NET 当作一种编译语言来运行,而不是解释性的语言,也可以编写强类型化的 JScript. NET代码。 有了 ASPNET后,就没有必要在服务器端的Wcb页面上使用脚语言了,但VBA仍用作 Oie文档和 Visual studio宏语言。 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第章 体系结构 和 从技术上讲,COM和COM+并不是面向NET的技术,因为基于它们的组件不能编 译为ⅡL(但如果原来的COM组件是用C艹编写的,使用托管CHt,在某种程度上可以这么 做)。但是,COM+仍然是一个重要的工具,因为其特性没有在NET中完全实现。另外, COM组件仍可以使用—NET组合了COM的互操作性,从而使托管代码可以调用COM 组件,COM组件也可以调用托管代码(见第33章)。在一般情况下,把新组件编写为.NET 组件,大多是为了方便,因为这样可以利用NET基类和托管代码的其他优点。 中间语 通过前面的学习,我们理解了 Microsoft中间语言显然在 net Framework中有非常重 要的作用。C开发人员应明白,C#代码在执行前要编泽为中间语言(实际上,C打编译器仅 编译为托管代码,这是有意义的,现在应详细讨论一下Ⅱ的主要特征,因为面向NET的 所有语言在逻辑上都需要支持LL的主要特征 下面就是中间语言的主要特征 面向对象和使用接凵 值类型和引用类型之间的巨大差别 ●强数据类型 使用异常来处理错误 使用特性( attribute) 下面详细讨论这些特征。 面向对象和接口的支持 NET的语言无关性还有一些实际的狠制。中间语言在设计时就打算实现某些特殊的编 程方法,这表示面向它的语言必须与编程方法兼容, Microsoft为IL选择的特定道路是传 统的面向对象的编程,带有类的单一继承性。 注意: 不熟悉面向对象概念的读者应参考附录A,获得更多的信息。附录A可以从 www.wroxcon上下载。 除了传统的面向对象编程外,中间语言还引入了接口的概念,它们显示了在带有COM 的 Windows下的第一个实现方式。NET接口与COM接口不同,它们不需要支持任何COM 基础结构,例如,它们不是派生自 IUnknown,也没有对应的GUID。但它们与COM接口 共享下述理念:提供一个契约,实现给定接口的类必须提供该接口指定的方法和属性的实 现方式 前面介绍了使用NET意味着要编译为中间语言,即需要使用传统的面向对象的方法来 编程。但这并不能提供语言的互操作性。毕竞,CH和Java都使用相同的面冋对象的范型, 但它们仍不是可交玍操作的语言ε卜面需要详细探讨一下语言互操作性的概念 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第Ⅰ部分语言 首先,需要确定一下语言互操作性的含义。毕竟,COM允许以不同语言编写的组件 起工作,即可以调用彼此的方法。这就足够了吗?COM是一个二进制标准,允许组件 实例化其他组件,调用它们的方法或属性,而无需考虑编写相关组件的语言。但为了实现 这个功能,每个对象都必须通过COM运行库来实例化,通过接口来访问。根据相关组件 的线程模型,不同线程上内存空间和运行组件之间要编组数据,这还可能造成很人的性能 损失。在极端情况下,组件保存为可执行文件,而不是DLL文件,还必须创建单独的进程 来运行它们。車要的是纽件要能与其他组件通信,但仅通过COM运行库进行通信。无论 COM是用于允许使用不同语言的组件直接彼此通信,或者创建彼此的实例,系统都把COM 作为中间件来处理。不仅如此,COM结构还不允许利用继承实现,即它丧失了面向对象 编程的许多优势。 一个相关的问题是,在调试时,仍必须单独调试用不同语言编写的组件。这样就不可 能在调试器上调试不同语言的代码了。语言互操作性的真正含义是用一种语言编与的类应 能直接与用另一种语言编写的类通信。特别是 用种语言编写的类应能继承用另种语言编写的类。 一个类应能包含另一个类的实例,而不管它们是使用什么语言编写的。 个对象应能直接调用用其他语言编写的另一个对象的方法。 对象(或对象的引用)应能在方法之间传递 在不同的语言之间调用方法时,应能在调试器中调试这些方法调用,即调试不同 语言编写的源代码。 这是一个雄心勃勃的日标,但令人惊讶的是,NET和中间语言己经实现了这个日标 在调试器上调试方法时,Ⅴ isual studio2005DE提供了这样的工具(不是CLR提供的 相异值类型和引用类型 与其他编程语言一样,中间语言提供了许多预定义的基木数据类型。它的一个特性是 值类型和引用类型有明显的区别。对于值类型,变量直接保存其数据,而对于引用类型 变量仅保存地址,对应的数据可以在该地址中找到。 在C艹+中,引用类犁类似于通过指针来访问变量,而在Ⅴ isual basic中,与引用类型 最相似的是对象, Visual basic6总是通过引用来访问对象。中间语言也有数据存储的规范: 引用类型的实例总是存储在一个名为“托管堆”的内存区域中,值类型一般存储在堆栈中(但 如果值类型在引用类型中声明为字段,它们就内联存储在堆中)。第2章“C#基础”讨论 堆栈和堆,及其工作原理 强数据类型 中间语言的一个重要方面是它基于强数据类型。所有的变量都清晰地标记为属于某个 特定数据类型(在中间语言中没有Ⅴ lal basic和脚本语言中的 Variant数据类型)。特别是 中间语言般不允许对模糊的数据类型执行任何操作。 例如, Visual basic6开发人员习惯于传递变量,而无需考虑它们的类型,因为 Visual 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第章 体系结构 Basic6会自动进行所需的类型转换。C++开发人员习惯于在不同类型之间转换指针类型 执行这类操作将大大提高性能,但破坏了类型的安全性。因此,这类操作只能在某些编译 为托管代码的语言中的特殊情况下进行。确实,指针(相对于引用)只能在标记了的C#代码 块中使用,但在 Visual basic中不能使用(但一般在托管C++中允许使用)。在代码中使用指 针会立即导致CLR提供的内存类型安全性检查失败。 注意,一些与NET兼容的语言,例如 Visual basic2005,在类型化方面的要求仍比较 松,但这是可以的,因为编译器在后台确保在生成的IL上强制类型安全 尽管强迫实现类型的安全性最初会降低性能,但在许多情況下,我们从NFT提供的、 依赖」类型安全的服务中获得的好处更多。这些服务包括: 语言的互操作性 垃圾收集 安全性 应用程序域 下面讨论强数据类型化对这些NET特性非常重要的原因 语言互操作性中强数据类型的重要性 如果类派生自其他类,或包含其他类的实例,它就需要知道其他类使用的所有数据类 型,这就是强数据类型非常重要的原因。实际上,过去没有任何系统指定这些信息,从而 成为语言继承和交互操作的貞止障碍。这类信息不只是在个标准的可执行文件或DLL 中出现 假定将 Visual basic2005类中的一个方法定义为返回一个整型— Visual basic2005可 以使用的标准数据类型之—。但C#没有该名称的数据类型。显然,我们只能从该类中派生, 再使用这个方法,如果编译器知道如何把 isual basic2005的整型类型映射为C#定义的某 种已知类型,就可以在C#代码中使用返回的类型。这个问题在.NET中是如何解决的? (1)通用类型系统(CTS) 这个数据类型问版在NET中使目通用类型系统(CTS)得到了解决。CTS定义了可以在 一中间语言中使用的颈定义数据类型,所有面向 NET Framework的语言都叫以生成最终基」 这些类型的编译代码 例如, Visual basic2005的整型实际上是一个32位有符号的整数,它实际映射为中间 语言类型Int32。因此在中间语言代码中就指定这种数据类型。C#编译器可以使用这种类 型,所以就不会有问题了。在源代码中,C#用关键字int来表示Int32,所以编译器就认为 Visual basic2005方法返回个int类型的值。 通用类型系统不仅指定了基本数据类型,还定义了一个内容丰富的类型层次结构,其 中包含设计合理的位置,在这些位置上,代码允许定义它自己的类型。通用类型系统的层 次结构反映了中问语言的单一继承的面向对象方法,如图1-1所示。 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第Ⅰ部分语言 类型 引用类型 接口关型 值类型 用户定义 指针类型 白我描述类型 闪詈值类型 的值类型 枚举 类类刑 数组 委托 装箱的值类型 用户定义的 引用类型 图 这个树形结构中的类型说明如表1-1所示。 类 开 含义 代表任何类型的基类 Value t 代表任何值类型的基类 Reference types 通过引用来访问,且存储在堆中的任何薮据类型 Built-in Value Types 包含人多数标准基本类型,可以表示数字、 Boolean值或字符 Enumerations 枚举值的集合 User-defined Value Types 在源代中定义,且保存为值类型的数据类型。在C#中,它表示结构 Interface Types 妾口 Pointer Types 指计 Self-describing types 为垃圾回收器提供对它们本身有益的信息的数据类型(参见下一节) Lys 包含对象数组的类型 Class Typcs 可白我描述的类型,但不是数组 Delegates 用于把引用包含在方法中的类型 User-definedReference Types在源代码中定义,且保存为引用类型的数据类型。在C中,它表示类 Boxed Value Type 值类型,临时打包放在一个引用中,以便于存储在堆中 这里没有列出内置的所有值类型,因为第3章将详细介绍它们。在C#中,编译器识别 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第章 体系结构 的每个预定义类型都映射为一个LL内置类型。这与Ⅴ visual basic2005是一样的。 (2)公共语言规范(CLS) 公共语言规范 Common Language Specification, CLS)和通用类型系统一起确保语言的 互操作性。CLS是一个最低标准集,所有面向NET的编译器都必须支持它。因为LL是 种内涵非常丰富的语言,人多数编译器的编写人员有可能把给定编译器的功能限制为只 支持LL和CLS提供的一部分特性。只要编译器支持已在CLS中定义的内容,这就是很 不错的。 提示 编写非CLS兼容代码应该是完全可以接受的,只是在编写了这种代码后,就不能保讧 编译好的I代码完全攴持语言的互操作性 下面的一个例子是有关区分大小写字母的。I是区分大小写的语言。使用这些语言的 丌发人员常常利用区分大小写所提供的灵活性来选择变量名。但 Visual basic2005是不区 分大小写的语言。CLS就要指定CLS兼容代码不使用任何只根据大小写来区分的名称。因 此, Isual basi2005代码可以与CLS兼容代码一起使用。 这个例子说明了CLS的两种工作方式。首先是各个编译器的功能不必强大到支 持NET的所有功能,这将鼓励人们为其他面向NET的编稈语言开发编译器。第二,它 提供如下保证:如果限制类只能使用CLS兼谷的特性,就要保证用其他语言编写的代码 可以使用这个类。 这种方法的优点是使用CIS兼容特性的限制只适用于公共和受保护的类成员和公共 类。在类的私有实现方式中,可以编写非CLS代码,因为其他程序集(托管代码的单元, 参见本章后面的内容)中的代码不能访问这部分代码 这里不深入讨论CLS规范。在一殷情况下,CLS对C代码的影响不会太大,因为C并 中的非CLS兼容特性非常少。 垃圾收集 垃圾收集器用来在NET中进行内存管理,特别是它可以恢复正在运行中的应用程序需 要的内存。到目前为止, Windows平台已经使用了两种技术释放进程向系统动态请求的 内存: 完全以于工方式使应用程序代码完成这些工作。 让对象维护引用计数。 让应用程序代码负责释放内存是低级高性能的语言使用的技术,例如C++。这种技术 很有效,且可以让资源在不需要时就释放(一般情况下),但其最大的缺点是频繁出现错误。 请求内存的代码还必须显式通知系统它什么时候不再需要该内存但这是很容易被遗漏的, 从而导致内存泄漏。 尽管现代的开发环境提供了帮助检测内存泄漏的L具,但它们很难跟踪错误,因为直 到内存已大量泄漏从而使 Windows拒绝为进程提供资源时,它们才会发挥作用。到那个时 候,由于对内存的需求很大,会使整个计算机变得相当慢。 维护引用计数是COM对象采用的一种技术,其方法是每个COM组件都保留一个计 互动出版网 www.china-pub.com China-Pub crm 专业图书网上第一专营店 独家提供样章 第Ⅰ部分语言 数,记录客户机目前对它的引用数。当这个计数下降到0时,组件就会删除自己,并释放 相应的内存和资源。它带来的问题是仍需要客户机通知组件它们已经完成了内存的使用 只要有一个客户机没有这么做,对象就仍驻留在内存中。在某些方面,这是比C+内存泄 漏更为严重的问题,因为COM对象可能存在于它自u的进程中,从来不会被系统删除(在 C++内存泄漏问题上,系统至少可以在进程中断时释放所有的内存)。 NE'运行库采用的方法是垃圾收集器,这是一个程序,其目的是清理内存,方法是所 有动态请求的内存都分配到堆上(所有的语言都是这样处理的,但在NET中,CLR维护它 自己的托管堆,以供NET应用程序使用),当NFT检测到给定进程的托管堆已满,需要清 理时,航调用垃墩收集器。垃圾收集器处理目前代码中的所有变量,检査对存储在托管堆 上的对象的引用,确定哪些对象可以从代码中访问——即哪些对象有引用。没有引用的对 象就不能再从代码中访问,因而被删除εJava就使用与此类似的垃圾收集系统。 之所以在NET中使用垃圾收集器,是因为中间语言已用来处理进程。其规则要求,第 不能引用已有的对象,除非复制已有的引用。第二,中间语言是类型安全的语言。在 这里,其含义是如果存在对对象的任何引用,该引用中就有足够的信息来桷定对象的类型 垃圾收集器机制不能和诸如非托管C+这样的语言一起使用,因为C→-允许指针自由 地转换数据类型。 垃圾收集器的一个重要方面是它的不确定性。换言之,不能保证什么时候会调用垃圾 收集器:NFT运行库决定需要它时,就可以调用它(除非明确调用垃圾收集器)。但可以重 写这个过程,在代码中调用垃圾收集器。 安全性 NET很好地补足了 Windows提供的安全机制,因为它提供的安全机制是基于代码的 安全性,而 Windows仅提供了基于角色的安全性。 基于角色的安全性建立在运行进程的账户的身份基础上,换言之,就是谁拥有和运行 进程。另一方面,基于代码的安全性建立在代码实际执行的任务和代码的可信程度上。由 于中间语言提供了强大的类型安全性,所以CLR可以在运行代码前检查它,以确定是否有 需要的安全权限。NET还提供了一种机制,可以在运行代码前指定代码需要什么安仝权限。 基于代码的安全性非常重要,原因是它降低了运行来历不明的代码的风险(例如代码是 从 Internet上下载来的)。即使代码运行在管理员账户下,也有可能使用基于代码的安全性, 来确定这段代码是否仍不能执行管理员账户一般允许执行的某些类型的操作,例如读写环 境变量、读写注册表或访问NFT反射特性 安全问题详见木书后面的第19章。 应用程序域 应用程序域是NET中的一个重要技术改进,它用」减少运行应用程序的系统廾销,这 些应用程序需要与其他程序分离开来,但仍需要彼此遥信。典型的例子是wcb服务器应用 程序,它需要同吋响应许多浏览器请求ε因此,要有许多组件实例冋时响应这些同吋运行 的请求。 在NET开发出来以前,可以让这些实例共享同一个进程,但此时一个运行的实例就有

...展开详情
试读 127P C#本质论(中文版)
立即下载 身份认证VIP会员低至7折
一个资源只可评论一次,评论内容不能少于5个字
您会向同学/朋友/同事推荐我们的CSDN下载吗?
谢谢参与!您的真实评价是我们改进的动力~
上传资源赚钱or赚积分
最新推荐
C#本质论(中文版) 10积分/C币 立即下载
1/127
C#本质论(中文版)第1页
C#本质论(中文版)第2页
C#本质论(中文版)第3页
C#本质论(中文版)第4页
C#本质论(中文版)第5页
C#本质论(中文版)第6页
C#本质论(中文版)第7页
C#本质论(中文版)第8页
C#本质论(中文版)第9页
C#本质论(中文版)第10页
C#本质论(中文版)第11页
C#本质论(中文版)第12页
C#本质论(中文版)第13页
C#本质论(中文版)第14页
C#本质论(中文版)第15页
C#本质论(中文版)第16页
C#本质论(中文版)第17页
C#本质论(中文版)第18页
C#本质论(中文版)第19页
C#本质论(中文版)第20页

试读结束, 可继续阅读

10积分/C币 立即下载