在 VisualStudio 中,程序集引用的“具体版本”属性是如何工作的?

今天,我仔细研究了 VisualStudio2010中程序集引用的“具体版本”属性。经过几次意想不到的实验后,我开始尽可能多地了解这个性质是如何工作的。即使如此,在我看来,并不是所有的答案,所以这里是我自我回答这个问题的尝试:

程序集引用的“特定版本”属性在 VisualStudio 中是如何工作的?

97113 次浏览

这是编译时属性!

需要知道的最重要的事情之一是,“具体版本”是一个在 编译时没有运行时生效的属性。

这都是为了什么?

生成项目时,需要解析项目的程序集引用,以便找到生成系统应使用的物理程序集。如果执行了“具体版本”检查(请参阅“何时检查了“具体版本”?”),它影响装配决议过程的结果:

  • 生成系统定位它可能使用的物理程序集
  • 生成系统将物理程序集的版本与存储在。用于程序集引用的 csproj 文件
  • 如果两个程序集版本完全相同,则解析过程成功,找到的物理程序集将用于生成
  • 如果两个程序集版本不匹配,则丢弃物理程序集,并通过定位下一个可能的程序集继续解析过程
  • 如果找不到更多可能的物理程序集,解析过程将失败。这将导致编译器警告(警告 MSB3245) ,告诉您无法解析引用。
  • 有趣的是,然后继续构建!如果代码没有对程序集的实际引用,那么构建就成功了(带有前面提到的警告)。如果代码具有引用,则生成失败,并出现一个错误,该错误看起来像是代码使用未知类型或命名空间。构建 真的失败的唯一原因是警告 MSB3245。

解析程序集的顺序

组装解析过程查找潜在组装的顺序如下:

  1. 由. csproj 文件中的 <HintPath>元素引用的程序集
  2. 项目输出路径
  3. GAC

注意,如果 GAC 中存在多个版本的程序集,解析过程首先尝试解析具有最高版本的程序集。只有在没有进行“特定版本”检查时,这一点才是重要的。

何时检查「特定版本」 ?

中找到的两条信息来决定是否执行“具体版本”检查。Csproj 文件:

  • <SpecificVersion>元素的存在与否及其值(如果存在)
  • 程序集引用中是否存在版本信息

具有版本信息的典型程序集引用如下:

<Reference Include="Foo, Version=1.2.3.4, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>True</SpecificVersion>
<HintPath>..\..\Bar\Foo.dll</HintPath>
</Reference>

这就是程序集引用看起来像 没有版本信息的样子:

<Reference Include="Foo">
[...]

下表显示何时执行“具体版本”检查,何时不执行。

                   |     Version information
|  Present       Not present
-------------------+------------------------------
<SpecificVersion>  |
- Present(=True)   |  1.Yes         2.Yes (check always fails)
- Present(=False)  |  3.No          4.No
- Not present      |  5.Yes         6.No

令人惊讶的是,如果同时缺少 <SpecificVersion>和版本信息,则不执行检查(情况6)。我希望检查被执行并且总是失败(与情况2相同) ,因为在我的理解中,缺少 <SpecificVersion>意味着默认值“ True”。这可能是我在 VisualStudio2010中进行测试时遇到的一个问题。

当您在 Visual Studio UI 中检查程序集引用的属性时(选择引用并按 F4) ,您看到的“具体版本”属性的值将告诉您 Visual Studio 是否将执行“具体版本”检查。在情况6中,UI 将显示“ True”,尽管。Csproj 文件。

“复制本地”的副作用

如果“ CopyLocal”属性设置为“ True”,但程序集解析过程由于“具体版本”检查而失败,则不复制任何程序集。

参考资料

添加引用后,VisualStudio 会在项目文件中记录程序集的[ AssemblyVersion ]。这很重要。如果您在一年后创建了一个 bug 修复程序,那么您需要确保使用与引用相同的 一模一样版本重新构建项目,这样它就是一个真正的插件。如果引用程序集已更改,则会得到一个错误。

但这并不总是令人满意的。有些程序员允许程序集版本自动递增,每次重新构建时都会生成一个新版本。即使程序集的公共接口从未更改。一些人通过使用 Nuget 来配置他们的项目来获取库,并且当有新的版本可用时让它自动更新库。他们希望将 SpectiveVersion 属性设置为 False 以禁止编译错误。

为了理解结果,您需要重新部署程序的整个构建以避免事故,这一点非常重要。运行时的版本不匹配会导致程序崩溃,只能在。配置文件,这是有风险的。