DotNetFramework大学题库 - 图文(8)

2019-02-21 00:30

第3章 托管代码的编译和执行

3.2.1 Microsoft 中间语言 (MSIL)

MSIL与处理器的本机指令集非常相似。但是,并不存在实际执行这些指令的任何硬件(至少到目前为止如此)。相反,MSIL代码在执行之前总是转换为相应的本机代码。可以客观地说,在.NET Framework环境中进行工作的开发人员并不需要完全理解MSIL。但是,我们至少要稍微了解一下编译器将基于C#、VB.NET 或任何其他基于CLR的语言编写的代码编译成MSIL的内容。

CLR所定义的抽象机器是基于堆栈的,这意味着很多 MSIL 操作是根据此堆栈定义的。 下面是一些示例 MSIL 指令及其用途:

? add:将堆栈上最上面的两个值相加,然后将结果压回堆栈。 ? box:将值类型转换为引用类型;即,将值装箱。 ? br:将控制(分支)转移到内存中的指定位置。 ? call:调用指定的方法。

? ldfld:将对象的指定字段加载到堆栈上。 ? ldobj:将指定值类型的值复制到堆栈上。 ? newobj:创建新对象或值类型的新实例。

? stfld:将一个值从堆栈复制到对象的指定字段中。 ? stobj:将堆栈上的某个值复制为指定的值类型。 ? unbox:将装箱值反向转换为其原始形式。

实际上,MSIL 是CLR的汇编语言。关于这些MSIL指令集值得注意的一点是,它与CLR的CTS抽象对应得很紧密。对象、值类型甚至是装箱和取消装箱都有直接支持。而且,某些操作(如用于创建新实例newobj)与高级语言中的某些极为常见的操作符相似,而这些操作方法在典型机器指令中很少见。

对于希望直接处理那些低级机器码的开发人员,.NET Framework 提供了称为 Ilasm 的 MSIL 汇编器。 不过,只有那些最喜欢折磨自己脑袋的开发员才会使用此工具,当然,需要进行极低级控制的开发人员也会使用。 既然可使用更简单、更强大的语言(如VB.NET或 C#)获得相同的结果,又何必用 MSIL 编写呢?

3.2.2 元数据

编译托管代码最终生成的是 MSIL和描述该代码的元数据。 元数据描述的是对应托管代码中定义的类型的信息,它与编译对应类型生成的 MSIL 存储在同一个文件中。图 3-3 显示了基于 CLR 的编译器生成的模块的抽象视图。 该文件包含了在源代码中定义的类型所生成的 MSIL 代码,这些类型同样是三个类 X、Y 和 Z。除了每个类中的各个方法相应代码外,该文件还包含描述这些类以及此文件中定义的任何其他类型的元数据。这些信息在该文件本身加载时载入内存,从而使元数据在运行时可供访问。CLR还可以从包含元数据的文件中直接读取元数据,这样即使代码未载入内存,这些信息仍然可用。 读取元数据的过程称为反射,这将在后续章节中更详细地描述。

27

.NET Framework 2.0 程序设计

图 3-3 模块包含文件中每种类型的元数据

元数据描述模块中包含的类型。 它为类型所存储的信息包括: ? 类型名称

? 类型可见性,可以是公共的或程序集 ? 此类型继承自哪个类型(如果存在) ? 该类型所实现的任何接口 ? 该类型所实现的任何方法 ? 该类型所公开的任何属性 ? 该类型提供的任何事件

元数据提供有关每个类型的详细信息。例如,每个方法的参数及其类型,还有该方法的返回值类型。

由于元数据总是存在,因此工具可相信它总是可用。例如,Visual Studio 2005使用元数据提供 IntelliSense 功能,该功能可向开发人员显示对于他所键入的类名有哪些相应的方法可用。 还可以使用 MSIL 反汇编器工具检查模块的元数据,该工具通常称为 Ildasm。 此工具是本章前面提到的Ilasm工具的反工具,它是 MSIL 的反汇编器,并且还可提供包含在特定模块中的元数据的详细显示。

3.2.3 属性

元数据中还包含属性。属性是存储在元数据中的值,可以使用属性来控制代码执行方式的各个方面,它与System.Attribute类相对应。属性(attribute)可添加到类型(如类)中,以及这些类型的字段、方法和属性(property)中。正如本书后面所述,.NET

Framework 类库依赖于属性完成很多事情,包括指定事务要求、指示哪些方法应公开为 SOAP 可调用的 Web 服务,以及描述安全性要求。 这些属性有标准名称和功能,它们是由使用这些属性的 .NET Framework 类库的各个部分所定义的。

开发人员还可以创建自定义属性,用于以特定于应用程序的方式控制其行为。 若要创建自定义属性,使用基于CLR的编程语言(如C#或VB.NET)的开发人员可定义继承 System.Attribute 的类。得到的类的实例将在编译时自动将其值存储在元数据中。

28

第3章 托管代码的编译和执行

3.3 组织托管代码:程序集(Assembly)

完整的应用程序通常由多个不同的文件组成。 某些文件是包含代码的 DLL 或 EXE 模块,而其他文件可能包含各种资源,如图像文件。 在 .NET Framework 应用程序中,构成逻辑功能单元的文件分组称为程序集。本节描述的程序集是开发、部署和运行.NET Framework 应用程序的基础。

3.3.1 程序集的元数据:清单(Manifest)

程序集是 .NET Framework 应用程序的构造块;是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元。程序集构成了部署、版本控制、重复使用、激活范围控制和安全权限的基本单元。事实上,不可能只通过查看目录列表就能判断哪些文件属于同一个程序集。相反,若要确定某个特定程序集是由哪些文件构成的,您需要检查该程序集的清单。如前所述,模块(如 DLL)中的元数据包含有关该模块中的类型的信息。与之相对应,程序集清单包含有关程序集中的所有模块和其他文件的信息。 换言之,清单是有关程序集的元数据。清单包含在程序集的一个文件中,并且它包含有关程序集以及构成该程序集的文件的信息。Visual Studio 2005之类的工具会为它所编译的每个模块生成元数据,同样它可以使用相应的清单生成程序集。

如图 3-4所示,程序集可以由单个文件构建,也可以由一组文件构建。 对于单文件程序集,清单存储在文件本身中。 而对于多文件程序集,清单存储在程序集的某个文件之中。 无论哪种情况,清单都描述整个程序集,而特定模块中的元数据只描述该模块内的类型。 程序集清单所包含的内容如下:

z 程序集的名称。所有程序集都有一个文本名称,同时可任意选用一个强名称,这

将在下一节描述。

z 程序集的版本号。此版本号的格式为 ..

number>.。例如,属于某个已发布应用程序的程序集的版本号可能为 1.2.1397.0。 请注意,版本号是按程序集编制的,不是按模块。 z 程序集的区域性,指示程序集所支持的文化或语言。

z 此程序集中所包含的所有文件的列表,同时附有根据这些文件计算出的哈希值。 z 此程序集所依赖的其他程序集,以及这些依赖程序集每一个的版本号。

29

.NET Framework 2.0 程序设计

图 3-4 一个程序集通常只是单个 DLL,但是它也可以包含多个文件

大多数程序集仅由一个 DLL 构成。但是,无论程序集包含一个文件还是多个文件,它在逻辑上都是一个不可分割的完整单元。程序集定义了用于界定类型的边界。对于 CLR,类型名称实际是由该类型的名称以及定义该类型的程序集的名称共同组成。

与 COM 类不同,这种程序集结构的一个重要的特性就是CLR 类没有相应的注册表项(除非为了向后兼容性,它们也可以作为 COM 类被访问)。当 CLR 需要查找某个其他程序集中的类时,它不会在注册表中查找该类。相反,它将根据一种定义良好(虽然稍有些复杂)的算法进行搜索,该算法将在本章后面描述。

不需要注册表项同时意味着安装程序集时只需要将其构成文件复制到目标计算机磁盘上的相应目录即可。同样,卸载程序集时通常也只需要删除其文件即可。与早期基于 COM 的应用程序不同,构建于 .NET Framework 的软件不需要修改系统注册表。

3.3.2 程序集分类

分类程序集的方法多种多样。有一种方法是将程序集划分为静态程序集和动态程序集。 静态程序集是由 Visual Studio 之类的工具生成的,并且其内容存储在磁盘上。大多数开发人员将创建静态程序集,因为其目标通常是构建可在一台或多台机器上安装并执行的应用程序。但是,我们也可以创建动态程序集。动态程序集的代码(和元数据)直接在内存中创建,并且可在创建时立即执行。创建之后,动态程序集可保存到磁盘上,然后再次加载并执行。最常见的动态程序集的示例可能是在ASP.NET处理.aspx 页面时所创建的那些程序集。

分类程序集的另一种方法是根据其命名方式来划分。任何程序集的完整命名需要指定三项: 程序集的名称、程序集的版本号,以及程序集所支持的区域性(如果提供了区域性)。所有程序集都有简单的文本名称,如“AccountAccess”,但是程序集也可以有强名称。强名称包含程序集名称的三个常规部分,但它还包含根据该程序集计算的数字签名以及用于创建该签名的私钥的对应公钥。强名称是惟一的,因此可用于无歧义地标识特定程

30

第3章 托管代码的编译和执行

序集。 如果需要,还可以将创建程序集数字签名的实体的证书嵌入程序集本身。这允许使用该程序集的任何人决定他们是否应该信任此实体,并因此而愿意执行该程序集。

具有强名称的程序集在加载时将由 CLR 自动检查其版本号。 但是,没有强名称的程序集的版本控制则应有创建和使用这些程序集的开发人员负责。 因为程序集有版本号,所以同一个程序集的多个版本可同时安装在同一台机器上。 而且,由于程序集可指定它所依赖的每个其他程序集的确切版本,因此在过去由于 DLL 冲突而导致的令人头疼的问题可降至最少。

在 .NET 之前,安装一个应用程序所需要的 DLL 的新版本通常会干扰依赖于同一个 DLL 的另一个应用程序。 人们将其戏称为“DLL 地狱”,而 .NET Framework 的目标之一就是解决此类问题。 通过使用具有强名称的程序集,基于 CLR 的应用程序可继续使用它所依赖的每个程序集的某个特定版本,同时不会限制其他应用程序使用新版本。 但是开发人员仍然需要小心,否则冲突仍可能会发生。 例如,假设一个程序集的两个版本都写入同一个临时文件。 除非它们就应如何共享此文件达成一致,否则同时运行这两个版本将引发问题。

3.4 执行托管代码

程序集提供了将包含 MSIL 和元数据的模块打包成部署单元的方法。 然而,编写代码的目的不是为了打包和部署,而是为了运行。 下面我们来了解一下运行托管代码的最重要的几个方面。

3.4.1 加载程序集

图 3-5 程序集搜索顺序

31


DotNetFramework大学题库 - 图文(8).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:胸怀天下事 满耳读书声 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: