CSharp-程序集简介

程序集

程序集内容

参考:程序集内容

通常,静态程序集可能由以下四个元素组成:

  • 1,程序集清单,包含程序集元数据。
  • 2,类型元数据。
  • 3,实现这些类型的 Microsoft 中间语言 (MSIL) 代码。
  • 4,资源集。

只有程序集清单是必需的,但也需要类型或资源来向程序集提供任何有意义的功能。

单文件程序集

assemblyover1.gif

多文件程序集

注意:Visual Studio IDE 只能用于创建单文件程序集。

将一个程序集的元素包含在几个文件中。 这些文件可以是应用程序所需的编译代码 (.netmodule)、资源(例如,.bmp 或 .jpg 文件)或其他文件的模块。

.NET Framework 只在文件被引用时下载该文件;通过将很少引用的代码保留在独立于应用程序的文件中来优化代码下载。

构成多文件程序集的那些文件实际上并非由文件系统来链接。 它们而是通过程序集清单进行链接,公共语言运行时将这些文件作为一个单元来管理。

assemblyover2.gif

在此插图中,所有三个文件均属于一个程序集,如 MyAssembly.dll 所包含的程序集清单文件中所述。 对于该文件系统,这三个文件是三个独立的文件。 请注意,文件 Util.netmodule 被编译为一个模块,因为它不包含任何程序集信息。 创建程序集之后,已将该程序集清单添加到指示程序集与 Util.netmodule 和 Graphic.bmp 之间关系的 MyAssembly.dll 中。

程序集清单

参考:程序集清单

每一程序集,无论是静态的还是动态的,均包含描述该程序集中各元素彼此如何关联的数据集合。 程序集清单就包含这些程序集元数据。 程序集清单包含指定该程序集的版本要求和安全标识所需的所有元数据,以及定义该程序集的范围和解析对资源和类的引用所需的全部元数据。 程序集清单可以存储在具有 Microsoft 中间语言 (MSIL) 代码的 PE 文件(.exe 或 .dll)中,也可存储在只包含程序集清单信息的独立 PE 文件中。

对于有一个关联文件的程序集,该清单将被合并到 PE 文件中以构成单文件程序集。

每一程序集的清单均执行以下功能:

  • 枚举构成该程序集的文件。
  • 控制对该程序集的类型和资源的引用,如何映射到包含其声明和实现的文件。
  • 枚举该程序集所依赖的其他程序集。
  • 在程序集使用者和程序集实现详细信息的使用者之间提供一定程度的间接性。
  • 呈现程序集自述。

程序集清单内容

信息 描述
程序集名称 指定程序集名称的文本字符串。
版本号 主版本号和次版本号,以及修订号和生成号。 公共语言运行时使用这些编号来强制实施版本策略。
culture 有关该程序集支持的区域性或语言的信息。此信息只应用于将一个程序集指定为包含特定区域性或特定语言信息的附属程序集。
强名称信息 如果已经为程序集提供了一个强名称,则为来自发行者的公钥。
程序集中所有文件的列表 在程序集中包含的每一文件的散列及文件名。 请注意,构成程序集的所有文件所在的目录
必须是包含该程序集清单的文件所在的目录。
类型引用信息 运行时用来将类型引用映射到包含其声明和实现的文件的信息。 该信息用于从程序集导出的类型。
有关被引用程序集的信息 该程序集静态引用的其他程序集的列表。 如果依赖的程序集具有强名称,
则每一引用均包括该依赖程序集的名称、程序集元数据(版本、区域性、操作系统等)和公钥。

全局程序集缓存

参考:全局程序集缓存

安装了公共语言运行时的每台计算机均具有计算机范围的代码缓存,称为全局程序集缓存。 全局程序集缓存中存储专门指定给由计算机中若干应用程序共享的程序集。

只能在需要时才通过将程序集安装到全局程序集缓存中来共享程序集。 一般原则是:程序集依赖项保持专用,并将程序集放在应用程序目录中,除非明确要求共享该程序集。 另外,无需为了使 COM 互操作或非托管代码可以访问程序集而将程序集安装到全局程序集缓存。

将组成应用程序的某个程序集置于全局程序集缓存中之后,无法再通过使用 xcopy 命令复制应用程序目录来复制或安装应用程序。 必须同时移动全局程序集缓存中的程序集。

可以通过两种方法将程序集部署到全局程序集缓存:

从 .NET Framework 4 开始,全局程序集缓存的默认位置为 %windir%\Microsoft.NET\assembly。 在 .NET Framework 的早期版本中,默认位置为 %windir%\assembly。

建议只允许具有“管理员”权限的用户从全局程序集缓存中删除文件。

部署在全局程序集缓存中的程序集必须使用强名称。 将程序集添加到全局程序集缓存时,可对组成该程序集的所有文件执行完整性检查。 缓存通过执行这些完整性检查来确保该程序集未被篡改,例如,文件已更改,但清单没有反映出此更改。

具有强名称的程序集

参考:具有强名称的程序集

强命名一个程序集可为程序集创建唯一的标识,并且可以防止程序集冲突。

强名称程序集通过使用私钥以及程序集本身生成,此私钥对应于与该程序集一起分发的公钥。 程序集包括程序集清单,此清单包含所有组成该程序集的文件的名称和哈希。 具有相同强名称的程序集应该完全相同。

在创建强名称程序集时,它包含程序集的简单文本名称、版本号、可选区域性信息、数字签名,以及对应于用于签名的私钥的公钥。

不要依赖于通过强名称实现安全性。 它们仅提供唯一的标识。

强命名程序集作用:

  • 你希望启用强名称程序集将引用的程序集,或希望允许其他强名称程序集 friend 访问你的程序集。
  • 应用程序需要访问同一程序集的各种版本。 这意味着你需要在同一应用程序域中并排加载某程序集的不同版本,且各版本互不冲突。 例如,如果在具有相同简单名称的程序集中存在 API 的不同扩展,强命名将为该程序集的每个版本提供唯一标识。
  • 你不希望程序集的使用对应用程序性能产生负面影响,所以你想要非特定于域的程序集。 这就要求进行强命名,因为非特定于域的程序集必须安装在全局程序集缓存中。
  • 如果你希望通过应用发布服务器策略来集中应用程序的服务,则意味着程序集必须安装在全局程序集缓存中。

程序集版本控制

使用公共语言运行时的程序集的所有版本控制都在程序集级别上进行。 一个程序集的特定版本和依赖程序集的版本在该程序集的清单中记录下来。 除非被配置文件(应用程序配置文件、发行者策略文件和计算机的管理员配置文件)中的显式版本策略重写,否则运行时的默认版本策略是,应用程序只与它们生成和测试时所用的程序集版本一起运行。

仅对具有强名称的程序集进行版本控制。

每一程序集都用两种截然不同的方法来表示版本信息:

  • 程序集的版本号,该版本号与程序集名称及区域性信息都是程序集标识的组成部分。 该号码将由运行时用来强制实施版本策略,它在运行时的类型解析进程中起着重要的作用。
  • 信息性版本,这是一个字符串,表示仅为提醒的目的而包括的附加版本信息。

程序集版本号

每一程序集都有一个版本号作为其标识的一部分。 因此,如果两个程序集具有不同的版本号,运行时就会将它们视作完全不同的程序集。

<主版本>.<次版本>.<生成号>.<修订版本>

例如,版本 1.5.1254.0 中的 1 表示主版本,5 表示次版本,1254 表示生成号,而 0 则表示修订号。

版本号与其他标识信息(包括程序集名称和公钥,以及与该应用程序所连接的其他程序集的关系和标识有关的信息)一起存储在程序集清单中。

在生成程序集时,开发工具将把每一个被引用程序集的依赖项信息记录在程序集清单中。 运行时将这些版本号与管理员、应用程序或发行者设置的配置信息结合使用,以加载被引用程序集的正确版本。

为进行版本控制,运行时会区分常规程序集和具有强名称的程序集。 只对具有强名称的程序集执行版本检查。