多文件程序集包含一个主 *.dll,它包含程序集清单。该多文件程序集的其他模块(按照约定,它们采用 *.netmodule 文件扩展名)被记录在主模块的清单中,并且由 CLR 按需加载。迄今为止,生成多文件程序集的唯一方式是使用命令行编译器。
为了说明该过程,请在 C:\MyCSharpCode 目录中创建一个名为 MultiFileAsm 的新子目录。我们的目标是创建一个名为 AirVehicles 的多文件程序集。主模块 (Airvehicles.dll) 将包含单个名为 Helicopter 的类类型(稍后定义)。程序集清单编录了一个附加模块 (ufos.netmodule),该模块定义了一个名为 UFO 的类类型:
// ufo.csusing System;using System.Windows.Forms;namespace AirVehicles{ public class UFO { public void AbductHuman() { MessageBox.Show("Resistance is futile"); } }}
要将 ufo.cs 编译为 .NET 模块,请指定 /t:module 作为目标类型,这会自动遵循 *.netmodule 命名约定(请回想一下,默认的响应文件自动引用 System.Windows.Forms.dll,因此我们不需要显式引用该库):
csc /t:module ufo.cs
如果您要将 ufo.netmodule 加载到 ildasm.exe 中,您会发现一个记载了该模块的名称和外部引用程序集的模块级别清单(请注意,*.netmodules 没有指定版本号,因为那是主模块的工作):
.assembly extern mscorlib{}.assembly extern System.Windows.Forms{}.module ufo.netmodule
现在,请创建一个名为 helicopter.cs 的新文件,该文件将用于编译主模块 Airvehicles.dll:
// helicopter.csusing System;using System.Windows.Forms;namespace AirVehicles{ public class Helicopter { public void TakeOff() { MessageBox.Show("Helicopter taking off!"); } }}
假设 Airvehicles.dll 是该多文件程序集的主模块,则您将需要指定 /t:library 标志。但是,因为您还希望将 ufo.netmodule 二进制文件编码到程序集清单中,所以您还必须指定 /addmodule 选项:
csc /t:library /addmodule:ufo.netmodule /out:airvehicles.dll helicopter.cs
如果您要分析 airvehicles.dll 二进制文件内部包含的程序集级别清单(使用 ildasm.exe),则会发现 ufo.netmodule 确实是使用 .file CIL 指令记录的:
.assembly airvehicles{}.file ufo.netmodule
多文件程序集的使用者可以较少关心他们要引用的程序集由大量二进制文件组成这一事实。实际上,在句法上将看起来与使用单文件程序集的行为完全相同。为了使本文变得更有趣一些,让我们创建一个基于 Windows 窗体的客户端应用程序。
返回页首我们的下一个示例项目将是一个使用 airvehicles.dll多文件程序集的 Windows 窗体应用程序。在 C:\MyCSharpCode 目录中创建一个名为 WinFormClient 的新的子目录。创建一个派生自 Form 的类,该类定义了单个 Button 类型,当它被单击时,将创建 Helicopter 和 UFO 类型,并且调用它们的成员:
using System;using System.Windows.Forms;using AirVehicles;public class MyForm : Form{ private Button btnUseVehicles = new Button(); public MyForm() { this.Text = "My Multifile Asm Client"; btnUseVehicles.Text = "Click Me"; btnUseVehicles.Width = 100; btnUseVehicles.Height = 100; btnUseVehicles.Top = 10; btnUseVehicles.Left = 10; btnUseVehicles.Click += new EventHandler(btnUseVehicles_Click); this.Controls.Add(btnUseVehicles); } private void btnUseVehicles_Click(object o,