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


155

今天,我仔细查看了Visual Studio 2010中程序集引用的“特定版本”属性。在进行了一些意想不到的结果的实验​​之后,我开始尽可能多地了解该属性的工作方式。在我看来,即使如此,也无法提供所有答案,因此这是我对问题的自我解答:

如何准确地做在Visual Studio程序集引用作品的“特定版本”属性?

Answers:


255

这是一个编译时属性!

其中一个知道的最重要的事情是,“特定版本”是,需要在效果的属性编译时运行时。

这是什么一回事呢?

生成项目时,需要解析项目的程序集引用,以便找到构建系统应使用的物理程序集。如果执行“特定版本”检查(请参阅“何时检查“特定版本”?”部分),这会影响程序集解析过程的结果:

  • 生成系统查找可能使用的物理程序集
  • 生成系统将物理程序集的版本与.csproj文件中存储的程序集版本进行比较,以供程序集引用
  • 如果两个程序集版本完全相同,则解析过程成功,并将找到的物理程序集用于构建
  • 如果两个装配体版本不匹配,则将丢弃物理装配体,并通过查找下一个潜在装配体继续进行解析过程
  • 如果找不到更多潜在的物理程序集,则解析过程将失败。这会导致编译器警告(警告MSB3245),告诉您无法解析该引用。
  • 有趣的是,构建然后继续!如果代码没有对程序集的实际引用,则构建成功(带有前面提到的警告)。如果代码具有引用,则构建将失败,并显示一个错误,看起来好像该代码正在使用未知类型或名称空间。为何构建真正失败的唯一迹象是警告MSB3245。

程序集解析的顺序

程序集解析过程查找潜在程序集的顺序似乎是这样的:

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

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

什么时候检查“特定版本”?

Visual Studio决定是否执行.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, has value True   |    Yes (1)        Yes (check always fails) (2)
- Present, has value False  |    No  (3)        No (4)
- Not present               |    Yes (5)        No (6)

令人惊讶的是,如果同时没有<SpecificVersion>和版本信息,则不执行任何检查(情况6)。我本来希望检查能够执行并且总是失败(与情况2相同),因为在我的理解中,没有<SpecificVersion>隐含默认值“ True”。这可能是我进行测试的Visual Studio 2010的古怪之处。

当您在Visual Studio UI中检查程序集引用的属性(选择引用并按F4键)时,看到的“特定版本”属性值将告诉您Visual Studio是否将执行“特定版本”检查。在情况6中,尽管<SpecificVersion>.csproj文件中不存在该元素,但UI将显示“ True” 。

“复制本地”的副作用

如果将“复制本地”属性设置为“真”,但是由于“特定版本”检查而导致程序集解析过程失败,则不会复制任何程序集。

参考资料


谢谢你的细节。我可以检查一下...程序集版本检查仅在具有强名称的程序集时进行;那正确吗?此外,当我们谈论检查的组件的版本-这是通过比较引用的程序集的做了名字?(在强名称程序集的情况下,该名称包含版本信息,因此它不像是在检查单独的版本字段吗?)
Gavin Hope

2
@GavinHope问题1:没有,(如果它缺少如版本检查不限于强名称,这主要是因为程序集名称可以包含版本,但仍然不强名称PublicKeyToken=的一部分)。另外,如果您在我的帖子末尾检查表格,您会发现即使Version=.csproj中的程序集名称中缺少零件,也可以进行版本检查。问题2:我假设程序集名称用于比较,是的。我不知道其他信息来源。
herzbube

“在第6种情况下,尽管.csproj文件中没有<SpecificVersion>元素,但UI将显示“ True”。-似乎默认值为True。将UI中的“特定版本”切换为True后,<SpecificVersion>标记将被完全省略,该标记以前的值为False
samis

@herzbube-我认为Visual Studio>“项目属性”窗口中“特定版本”的含义与您在此处所说的相反(与您期望的相反)。Visual Studio表示“特定版本”的值(是或否)“表示是否可以在不考虑程序集解析的多目标规则的情况下解析该程序集”。
N73k

35

添加引用后,Visual Studio会将程序集的[AssemblyVersion]记录在项目文件中。这个很重要。例如,如果您在一年后创建错误修复,那么您要确保使用与参考完全相同的版本来重建项目,这样才是真正的插件。如果参考部件已更改,则会出现错误。

但这并不总是可取的。一些程序员让程序集版本自动递增,从而在每次重建时生成一个新版本。即使程序集的公共接口从未更改。有些人使用Nuget来获取库来配置他们的项目,并在有新版本发布时让它自动更新库。他们希望将“特定版本”属性设置为False,以抑制编译错误。

要了解后果非常重要,您确实需要重新部署程序的整个内部版本以避免发生意外。在运行时版本不匹配会使程序崩溃,并且只能通过<bindingRedirect>.config文件中的带有风险的抑制。


2
感谢您提供信息,为什么 “特定版本”很重要,这是我在回答中涉及的纯机械方面的良好伴侣。
herzbube 2014年

@Hans Passant-您的最后一段对SpecificVersion是否有效?我认为将这些设置为true会导致这些结果。
GreenEyedAndy

1
SpecificVersion仅适用于构建您的应用程序。在运行时,CLR始终坚持与参考程序集版本号完全匹配。如果您在构建时使用了较新的版本,则在运行时也必须是该较新的版本。
汉斯·帕桑

1
提防VS2013&.Net 4.5.1 AutoGenerateBindingRedirects即使您告诉它使用特定版本,他们也可能会将dll绑定重定向到较新版本
Dennis Kuypers

1
@HansPassant我认为[AssemblyVersion]当程序集未使用强名称签名时,CLR不考虑在内。
tm1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.