22.2 程序集
学习了如何使用逻辑的方法组织、管理众多的类型后,我们继续学习如何使用程序集进行组织、管理,这是一种物理层次上的组织方法。程序集构成了部署、版本控制、重复使用、激活范围控制和安全权限的基本单元。一个程序集可能是一个exe文件,或者一个dll类库,它们都是可执行(PE)文件。一个程序集可以包含一个或多个模块。一般情况下一个程序集包含一个模块,也可以创建多模块(多文件)程序集。程序集包括了公共语言运行时需要了解的各种重要信息,例如程序集的名称、类型引用等信息,我们会在22.2.2节进行具体介绍。注意,每个程序集都只能有一个入口点(Entry),exe文件的入口点为Main方法,而dll类库并不包含Main方法。
程序集必须被加载到应用程序域才能运行,关于应用程序域将在22.2.4节进行介绍。程序集的加载过程比较复杂,我们只能了解这样一个大致的过程。图22-3中演示了程序集加载的大致过程。需要说明的是,一个程序集仅在需要时才会被加载,是按需加载的,如果一个程序集没有被用到,则不会被加载。
接下来,我们对图22-3进行简单说明。程序集的加载过程大致是这样的:
图 22-3 程序集搜索顺序
(1)第一步,检查各种配置文件,目的是确定程序集的正确版本。如果配置文件位于远程服务器,就需要首先下载这些配置文件,然后进行检查。在确定了程序集的版本后,搜索将继续。
(2)第二步,CLR会检查这个程序集是否此前就已经被加载,如果已加载,就使用此前加载的程序集,搜索过程就此结束。否则,CLR将判断是否此前曾经试图加载该程序集但却未成功,如果结果为是则不再尝试继续加载该程序集,加载直接以失败告终。否则,搜索将继续。
(3)第三步,在全局程序集缓存(GAC)中尝试搜索程序集,如果找到则加载它,否则搜索将继续。
(4)第四步,在第一步中CLR已经通过配置文件确定了程序集的正确版本,现在将回过头来,继续在配置文件中寻找是否存在<codeBase>元素(<codeBase>元素的作用是指定公共语言运行时可以在何处找到程序集的位置)。如果存在,CLR将立刻检查codeBase元素指定的位置,如果在这个位置找到了正确的程序集,那么将加载它,搜索过程结束。否则,搜索将停止,加载失败。但如果<codeBase>元素不存在,搜索仍将继续。以下是codeBase在配置文件中的示例。
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="neutral"/>
<codeBase version="2.0.0.0"
href="http://www.someurl.com/SomeAssembly.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
(5)最后,CLR将会搜索一个叫做“应用程序基(Application Base)”的位置,该位置可能是应用程序所在的根目录,也可能是一个URL,因为CLR并不假定所有需要的程序集都在一台计算机上,而非在远程计算机上。如果CLR在应用程序基中也没有找到正确的程序集,CLR将继续搜索其他的目录,并根据区域性信息、程序集名称等信息继续搜索,也包括这些目录的子目录。搜索的目录包括:
❑[应用程序基]/[程序集名称].dll
❑[应用程序基]/[程序集名称]/[程序集名称].dll
❑[应用程序基]/[区域性]/[程序集名称].dll
❑[应用程序基]/[区域性]/[程序集名称]/[程序集名称].dll
另外,CLR还会在配置文件中搜索使用<probing>元素的privatePath特性所指定的目录,使用privatePath特性指定的目录必须是应用程序根目录的子目录,可以包含区域性信息。CLR一旦找到一个与引用的简单程序集名称匹配的程序集时就停止搜索,无论该匹配正确与否。如果该程序集是正确的匹配项,就使用它。否则,则停止搜索,加载失败。
22.2.1 程序集的结构
程序集分为静态程序集和动态程序集。静态程序集存储于磁盘上的可执行(Portable Executable,PE)文件中,动态程序集我们将22.2.5节进行学习。先来看看静态程序集由哪些元素组成,主要组成部分如下:
❑程序集清单,包含程序集的元数据
❑类型元数据
❑CIL代码
❑资源
这些组成部分不一定在同一个物理文件中,也不一定在一个物理文件中,可能分布于多个物理文件中,因此程序集又分为单文件程序集和多文件程序集。单文件程序集将包括所有这些元素,如图22-4所示。
图 22-4 单文件程序集的组成
多文件程序集,就是其中一部分元素分布在几个物理文件中,可能是模块(.netmodule)或资源文件(如jpg等图片文件)。要注意的是,构成多文件程序集的那些文件实际上并非由文件系统来链接,而是通过程序集清单进行链接,公共语言运行时将这些文件作为一个单元来管理。
对于一个多文件程序集,程序集可以只包含“程序集清单”,也必须要包含,然后把其他元素放入其他的物理文件中。如图22-5所示,模块代表一个.netmodule文件,而资源代表某个图片文件。所有这三个文件均属于同一个程序集。对于该文件系统,这三个文件是三个独立的文件。其中模块中不包含任何程序集信息。在创建了程序集后,该程序集清单就被添加到程序集,该清单负责指示程序集与“模块”和“资源”的关系。
图 22-5 多文件程序集的组成
CLR只在文件被引用时才下载该文件,因此可以将很少引用的代码分离到在独立于应用程序的文件中来优化代码下载,有时不失为一种好的策略。在设计时,也可以根据实际情况做出类似的决定,即如何将应用程序的功能划分到一个或多个程序集中。