【发布时间】:2013-03-09 17:48:56
【问题描述】:
在物理上编码为多个 .cs 文件的单个文件程序集与具有多个 .NetModules 的多文件程序集之间有什么区别和优势?
我的教授说,当这些程序集被加载或在 jitting 期间可以实现差异。并非多文件程序集的所有 .Netmodules 都会立即加载。但即使是他也不确定。谁能给我解释一下?
【问题讨论】:
标签: .net assemblies .net-assembly
在物理上编码为多个 .cs 文件的单个文件程序集与具有多个 .NetModules 的多文件程序集之间有什么区别和优势?
我的教授说,当这些程序集被加载或在 jitting 期间可以实现差异。并非多文件程序集的所有 .Netmodules 都会立即加载。但即使是他也不确定。谁能给我解释一下?
【问题讨论】:
标签: .net assemblies .net-assembly
假设我们有两个名为 RUT.cs 的 .cs 文件,其中包含很少使用的类型 FUT.cs,其中包含经常使用的类型
现在csc /t:module RUT.cs
此行导致 C# 编译器创建 RUT.netmodule 文件。这个文件是一个标准的 DLL PE
文件,但 CLR 本身无法加载它。
接下来让我们将常用的类型编译到它们自己的模块中。我们将制作这个模块
程序集清单的保管者,因为这些类型经常使用。事实上,因为
这个模块现在将代表整个程序集,我将输出文件的名称更改为
JeffTypes.dll 而不是调用它 FUT.dll:
csc /out:JeffTypes.dll /t:library /addmodule:RUT.netmodule FUT.cs
这一行告诉 C# 编译器编译 FUT.cs 文件以生成 JeffTypes.dll 文件。 因为指定了 /t:library,所以包含清单元数据表的 DLL PE 文件是 发射到 JeffTypes.dll 文件中。 /addmodule:RUT.netmodule 开关告诉编译器 RUT.netmodule 是一个应该被视为程序集一部分的文件。具体来说, /addmodule 开关告诉编译器将文件添加到 FileDef 清单元数据表 并将 RUT.netmodule 的公开导出类型添加到 ExportedTypesDef 清单 元数据表。
RUT.netmodule 文件包含编译 RUT.cs 生成的 IL 代码。这个文件也
包含描述类型、方法、字段、属性、事件等的元数据表
由 RUT.cs 定义。元数据表还描述了类型、方法和
RUT.cs 引用的等等。 JeffTypes.dll 是一个单独的文件。像 RUT.netmodule,
该文件包括编译 FUT.cs 生成的 IL 代码,还包括类似的定义
和参考元数据表。但是,JeffTypes.dll 包含额外的清单
元数据表,使 JeffTypes.dll 成为一个程序集。额外的清单元数据表
描述组成程序集的所有文件(JeffTypes.dll 文件本身和
RUT.netmodule 文件)。清单元数据表还包括所有公共类型
从 JeffTypes.dll 和 RUT.netmodule 导出
现在,如果一些引用 JeffTypes.dll 的客户端代码正在执行,
当一个方法第一次被调用时,
CLR 检测方法引用的类型作为参数、返回值或作为
局部变量。然后 CLR 尝试加载引用的程序集的文件,该文件包含
显现。如果被访问的类型在这个文件中,CLR 执行它的内部簿记,
允许使用该类型。如果清单表明引用的类型在不同的
文件,CLR 尝试加载必要的文件,执行其内部簿记,并
允许访问该类型。 CLR 仅在方法引用时加载程序集文件
卸载程序集中的一个类型被调用。
这意味着要运行应用程序,所有文件
来自被引用程序集的不需要存在。
因此,较少使用的源类可以在 NetModules 中编译并在必要时加载,从而提高性能和更少的 Dll 文件大小简化了更改管理和部署过程 .
图片和部分引述来自 jeffrey richter
【讨论】: