程序集引用的“特定版本”属性在 Visual Studio 中究竟是如何工作的?
Posted
技术标签:
【中文标题】程序集引用的“特定版本”属性在 Visual Studio 中究竟是如何工作的?【英文标题】:How exactly does the "Specific Version" property of an assembly reference work in Visual Studio? 【发布时间】:2014-07-24 04:48:11 【问题描述】:今天,我仔细研究了 Visual Studio 2010 中程序集引用的“特定版本”属性。经过一些意外结果的实验后,我开始尽可能多地了解该属性的工作原理。即使如此,在我看来,也没有所有的答案,所以这是我尝试自我回答这个问题:
程序集引用的“特定版本”属性究竟如何在 Visual Studio 中工作?
【问题讨论】:
【参考方案1】:这是一个编译时属性!
要知道的最重要的事情之一是,“特定版本”是在编译时而不是在运行时不生效的属性。
这是怎么回事?
构建项目时,需要解析项目的程序集引用,以便找到构建系统应使用的物理程序集。如果执行“特定版本”检查(参见“何时检查“特定版本”?”一节),它会影响程序集解析过程的结果:
构建系统找到它可能使用的物理程序集 构建系统将物理程序集的版本与 .csproj 文件中存储的程序集版本进行比较,以供程序集参考 如果两个程序集版本完全相同,则解析过程成功,找到的物理程序集用于构建 如果两个程序集版本不匹配,则丢弃物理程序集并通过定位下一个潜在程序集继续解决过程 如果找不到更多潜在的物理程序集,解析过程将失败。这会导致编译器警告(警告 MSB3245)告诉您无法解析引用。 有趣的是,然后构建继续!如果代码没有对程序集的实际引用,则构建成功(带有前面提到的警告)。如果代码有引用,则构建失败并出现错误,看起来好像代码使用了未知类型或命名空间。构建真正失败的唯一迹象是警告 MSB3245。程序集的解析顺序
程序集解析过程定位潜在程序集的顺序如下:
-
.csproj 文件中
<HintPath>
元素引用的程序集
项目输出路径
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(=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”。这可能是我在其中进行测试的 Visual Studio 2010 的一个怪癖。
当您在 Visual Studio UI 中检查程序集引用的属性时(选择引用并按 F4),您看到的“特定版本”属性值会告诉您 Visual Studio 是否要执行“特定版本”检查。在案例 6 中,UI 将显示“True”,尽管 .csproj 文件中不存在 <SpecificVersion>
元素。
“复制本地”的副作用
如果“复制本地”属性设置为“真”,但程序集解析过程由于“特定版本”检查而失败,则不会复制任何程序集。
参考资料
What you need to know about referenced assemblies in VS2005(blogs.msdn.com 文章) What's New in .NET 2.0 for Assemblies and Versioning?(codemag.com 文章复制了上述 MSDN 文章,只包含措辞,但包含一些屏幕截图和有关程序集版本控制的其他信息)【讨论】:
“在案例 6 中,UI 将显示“True”,尽管 .csproj 文件中不存在<SpecificVersion>
标记被完全省略,之前的值为 False。
@herzbube - 我认为 Visual Studio > Project Properties 窗口中“特定版本”的含义与您在此处所说的相反(这与您所期望的相反) . Visual Studio 表示“特定版本”的值(true 或 false)“指示是否可以不考虑解决程序集解析的多目标规则”。
@herzbube 关于决议顺序,GAC 不是第一个检查的地方吗?还是仅适用于运行时?这不会造成编译时和运行时不同步吗?
@joe 在我写这篇文章的时候,我确信顺序和我描述的一样。如果您对更现代的 Visual Studio 版本中的当前行为有疑问,请自行调查。关于你提到的“不同步”——我看不出这怎么可能是个问题。编译器会将引用嵌入到它使用的任何程序集,然后也将在运行时使用。如果这不是您期望的参考,那么您的构建系统设置不当。如果您需要对该主题进行更多详细说明,请提出一个新问题 - cmets 是一种糟糕的问答格式。【参考方案2】:
当您添加引用时,Visual Studio 会在项目文件中记录程序集的 [AssemblyVersion]。这个很重要。例如,如果您在一年后创建一个错误修复程序,那么您希望确保使用 exact 相同版本的参考重新构建项目,以便它是一个真正的插件。如果引用程序集已更改,您将收到错误消息。
但这并不总是可取的。一些程序员让汇编版本自动增加,每次重建时都会生成一个新版本。即使程序集的公共接口从未改变。有些人通过使用 Nuget 来配置他们的项目来获取库,并让它在有新版本可用时自动更新库。他们希望将 Specific Version 属性设置为 False 以抑制编译错误。
了解后果非常重要,您确实需要重新部署程序的整个构建以避免发生意外。运行时的版本不匹配会使程序崩溃,只能在 .config 文件中使用 <bindingRedirect>
来抑制,这是有风险的。
【讨论】:
感谢您提供信息为什么“特定版本”很重要,这是我在回答中涉及的纯机械方面的好伴侣。 @Hans Passant - 您的最后一段是否适用于 SpecificVersion True 或 False?我认为这些是您将其设置为 true 时的后果。 SpecificVersion 仅适用于构建您的应用程序。在运行时,CLR 始终坚持与参考程序集版本号完全匹配。如果您在构建时使用了较新的版本,那么它也需要在运行时使用较新的版本。 当心 VS2013 和 .Net 4.5.1 AutoGenerateBindingRedirects 即使您告诉它使用特定版本,它们也可能会将 dll 绑定重定向到较新的版本 @HansPassant 我认为当程序集没有强名称签名时,CLR 不会考虑[AssemblyVersion]
。以上是关于程序集引用的“特定版本”属性在 Visual Studio 中究竟是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 8 中程序集引用的 Aliases 属性有啥用
如何在 Visual Studio 中将源附加到引用的程序集
Visual Studio 2010 程序集签名:尝试引用不存在的令牌