分类

链接

2011 年 12 月
 1234
567891011
12131415161718
19202122232425
262728293031  

近期文章

热门标签

新人福利,免费薅羊毛

现在位置:    首页 > .NET > 正文
共享办公室出租
深入.net实质讨论系列(五)
.NET 暂无评论 阅读(1,640)

第1章 .NET体系结构

(5) COM和COM+

从技术上讲,COM 和 COM+并不是面向.NET 的技术,因为基于它们的组件不能编译为IL(但如果原来的COM组件是用C++编写的,使用托管C++,在某种程度上可以这么做)。但是,COM+仍然是一个重要的工具,因为其特性没有在.NET中完全实现。另外,COM组件仍可以使用——.NET组合了COM的互操作性,从而使托管代码可以调用COM组件,COM组件也可以调用托管代码(见第33章)。在一般情况下,把新组件编写为.NET组件,大多是为了方便,因为这样可以利用.NET基类和托管代码的其他优点。

1.3 中间语言

通过前面的学习,我们理解了Microsoft中间语言显然在.NET Framework中有非常重要的作用。C#开发人员应明白,C#代码在执行前要编译为中间语言(实际上,C#编译器仅编译为托管代码),这是有意义的,现在应详细讨论一下IL的主要特征,因为面向.NET的所有语言在逻辑上都需要支持IL的主要特征。

下面就是中间语言的主要特征:

● 面向对象和使用接口

● 值类型和引用类型之间的巨大差别

● 强数据类型

● 使用异常来处理错误

● 使用特性(attribute)

下面详细讨论这些特征。

1.3.1 面向对象和接口的支持

.NET的语言无关性还有一些实际的限制。中间语言在设计时就打算实现某些特殊的编程方法,这表示面向它的语言必须与编程方法兼容,Microsoft为IL选择的特定道路是传统的面向对象的编程,带有类的单一继承性。

注意:

不熟悉面向对象概念的读者应参考附录 A,获得更多的信息。附录 A 可以从www.wrox.com上下载。

除了传统的面向对象编程外,中间语言还引入了接口的概念,它们显示了在带有COM的Windows下的第一个实现方式。.NET接口与COM接口不同,它们不需要支持任何COM基础结构,例如,它们不是派生自IUnknown,也没有对应的GUID。但它们与COM接口共享下述理念:提供一个契约,实现给定接口的类必须提供该接口指定的方法和属性的实现方式。

前面介绍了使用.NET意味着要编译为中间语言,即需要使用传统的面向对象的方法来编程。但这并不能提供语言的互操作性。毕竟,C++和Java都使用相同的面向对象的范型,但它们仍不是可交互操作的语言。下面需要详细探讨一下语言互操作性的概念。

7 第Ⅰ部分 C# 语 言

首先,需要确定一下语言互操作性的含义。毕竟,COM允许以不同语言编写的组件一起工作,即可以调用彼此的方法。这就足够了吗?COM 是一个二进制标准,允许组件实例化其他组件,调用它们的方法或属性,而无需考虑编写相关组件的语言。但为了实现这个功能,每个对象都必须通过COM运行库来实例化,通过接口来访问。根据相关组件的线程模型,不同线程上内存空间和运行组件之间要编组数据,这还可能造成很大的性能损失。在极端情况下,组件保存为可执行文件,而不是DLL文件,还必须创建单独的进程来运行它们。重要的是组件要能与其他组件通信,但仅通过COM运行库进行通信。无论COM是用于允许使用不同语言的组件直接彼此通信,或者创建彼此的实例,系统都把COM作为中间件来处理。不仅如此,COM结构还不允许利用继承实现,即它丧失了面向对象编程的许多优势。

一个相关的问题是,在调试时,仍必须单独调试用不同语言编写的组件。这样就不可能在调试器上调试不同语言的代码了。语言互操作性的真正含义是用一种语言编写的类应能直接与用另一种语言编写的类通信。特别是:

● 用一种语言编写的类应能继承用另一种语言编写的类。

● 一个类应能包含另一个类的实例,而不管它们是使用什么语言编写的。

● 一个对象应能直接调用用其他语言编写的另一个对象的方法。

● 对象(或对象的引用)应能在方法之间传递。

● 在不同的语言之间调用方法时,应能在调试器中调试这些方法调用,即调试不同

语言编写的源代码。

这是一个雄心勃勃的目标,但令人惊讶的是,.NET和中间语言已经实现了这个目标。在调试器上调试方法时,Visual Studio 2005 IDE提供了这样的工具(不是CLR提供的)。1.3.2 相异值类型和引用类型

与其他编程语言一样,中间语言提供了许多预定义的基本数据类型。它的一个特性是值类型和引用类型有明显的区别。对于值类型,变量直接保存其数据,而对于引用类型,变量仅保存地址,对应的数据可以在该地址中找到。

在C++中,引用类型类似于通过指针来访问变量,而在Visual Basic中,与引用类型最相似的是对象,Visual Basic 6总是通过引用来访问对象。中间语言也有数据存储的规范:引用类型的实例总是存储在一个名为“托管堆”的内存区域中,值类型一般存储在堆栈中(但如果值类型在引用类型中声明为字段,它们就内联存储在堆中)。第2章“C#基础”讨论堆栈和堆,及其工作原理。

1.3.3 强数据类型

中间语言的一个重要方面是它基于强数据类型。所有的变量都清晰地标记为属于某个特定数据类型(在中间语言中没有Visual Basic和脚本语言中的Variant数据类型)。特别是中间语言一般不允许对模糊的数据类型执行任何操作。

例如,Visual Basic 6开发人员习惯于传递变量,而无需考虑它们的类型,因为Visual8

第1章 .NET体系结构Basic 6会自动进行所需的类型转换。C++开发人员习惯于在不同类型之间转换指针类型。执行这类操作将大大提高性能,但破坏了类型的安全性。因此,这类操作只能在某些编译为托管代码的语言中的特殊情况下进行。确实,指针(相对于引用)只能在标记了的C#代码块中使用,但在Visual Basic中不能使用(但一般在托管C++中允许使用)。在代码中使用指针会立即导致CLR提供的内存类型安全性检查失败。

注意,一些与.NET兼容的语言,例如Visual Basic 2005,在类型化方面的要求仍比较松,但这是可以的,因为编译器在后台确保在生成的IL上强制类型安全。

尽管强迫实现类型的安全性最初会降低性能,但在许多情况下,我们从.NET提供的、依赖于类型安全的服务中获得的好处更多。这些服务包括:

● 语言的互操作性

● 垃圾收集

● 安全性

● 应用程序域

下面讨论强数据类型化对这些.NET特性非常重要的原因。

1. 语言互操作性中强数据类型的重要性

如果类派生自其他类,或包含其他类的实例,它就需要知道其他类使用的所有数据类型,这就是强数据类型非常重要的原因。实际上,过去没有任何系统指定这些信息,从而成为语言继承和交互操作的真正障碍。这类信息不只是在一个标准的可执行文件或 DLL中出现。

假定将Visual Basic 2005类中的一个方法定义为返回一个整型——Visual Basic 2005可以使用的标准数据类型之一。但C#没有该名称的数据类型。显然,我们只能从该类中派生,再使用这个方法,如果编译器知道如何把Visual Basic 2005的整型类型映射为C#定义的某种已知类型,就可以在C#代码中使用返回的类型。这个问题在.NET中是如何解决的?

(1) 通用类型系统(CTS)

这个数据类型问题在.NET中使用通用类型系统(CTS)得到了解决。CTS定义了可以在中间语言中使用的预定义数据类型,所有面向.NET Framework的语言都可以生成最终基于这些类型的编译代码。

例如,Visual Basic 2005的整型实际上是一个32位有符号的整数,它实际映射为中间语言类型 Int32。因此在中间语言代码中就指定这种数据类型。C#编译器可以使用这种类型,所以就不会有问题了。在源代码中,C#用关键字int来表示Int32,所以编译器就认为Visual Basic 2005方法返回一个int类型的值。

通用类型系统不仅指定了基本数据类型,还定义了一个内容丰富的类型层次结构,其中包含设计合理的位置,在这些位置上,代码允许定义它自己的类型。通用类型系统的层次结构反映了中间语言的单一继承的面向对象方法,如图1-1所示。

============ 欢迎各位老板打赏~ ===========

本文版权归Bruce's Blog所有,转载引用请完整注明以下信息:
本文作者:Bruce
本文地址:深入.net实质讨论系列(五) | Bruce's Blog

发表评论

留言无头像?