程序集引用的"特定版本"属性在Visual Studio中的工作原理是什么?

her*_*ube 143 .net visual-studio

今天,我仔细研究了Visual Studio 2010中程序集引用的"特定版本"属性.经过一些意外结果的实验​​后,我开始尽可能多地了解该属性的工作原理.即便如此,在我看来,并没有得到所有的答案,所以这是我尝试自我回答这个问题:

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

her*_*ube 236

这是一个编译时的属性!

一要知道最重要的事情是,"特定版本"是,需要在效果的属性编译时运行时.

这是什么一回事呢?

构建项目时,需要解析项目的程序集引用,以便查找构建系统应使用的物理程序集.如果执行"特定版本"检查(请参阅"何时"特定版本"选中?"部分),则会影响装配解决过程的结果:

  • 构建系统定位它可能使用的物理程序集
  • 构建系统将物理程序集的版本与存储在.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>
Run Code Online (Sandbox Code Playgroud)

这就是没有版本信息时程序集引用的样子:

<Reference Include="Foo">
[...]
Run Code Online (Sandbox Code Playgroud)

下表显示执行"特定版本"检查的时间,以及何时不执行.

                            |     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)
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,如果<SpecificVersion>不存在和版本信息,则不执行检查(案例6).我本以为要执行检查并且总是失败(与案例2相同),因为在我的理解中,缺少<SpecificVersion>意味着默认值"True".这可能是Visual Studio 2010的一个怪癖,我在那里进行了测试.

在Visual Studio UI中检查程序集引用的属性(选择引用并按F4)时,您在"特定版本"属性中看到的值会告诉您Visual Studio是否要执行"特定版本"校验.在案例6中,UI将显示"True",尽管该<SpecificVersion>元素不存在于.csproj文件中.

对"复制本地"的副作用

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

参考资料

  • @GavinHope问题1:不,版本检查不仅限于强名称,主要是因为程序集名称可以包含版本但仍然不是强名称(例如,如果它缺少`PublicKeyToken =`部分).此外,如果您在我的帖子末尾检查表格,您可以看到即使.csproj中的程序集名称中缺少`Version =`部分,也可能发生版本检查.问题2:我假设程序集名称用于比较,是的.我不知道有任何其他信息来源. (2认同)

Han*_*ant 34

添加引用时,Visual Studio会在项目文件中记录程序集的[AssemblyVersion].这个很重要.例如,如果您在一年后创建了一个错误修复程序,那么您需要确保使用完全相同的引用版本重新构建项目,这样才能真正实现这一目标.如果引用程序集已更改,您将收到错误.

但这并不总是令人满意的.一些程序员让程序集版本自动递增,每次重建时都会生成一个新版本.尽管程序集的公共接口从未改变过.有些人通过使用Nuget获取库来配置他们的项目,并在有新版本可用时让它自动更新库.他们希望将Specific Version属性设置为False以抑制编译错误.

了解后果非常重要,您需要重新部署整个程序版本以避免事故.运行时版本不匹配导致程序崩溃,只能使用<bindingRedirect>.config文件中的a进行抑制,这样做有风险.

  • 感谢信息_why_"特定版本"很重要,这是我在答案中涵盖的纯机械方面的良好伴侣. (2认同)
  • SpecificVersion 仅适用于构建您的应用程序。在运行时,CLR 始终坚持与参考程序集版本号完全匹配。如果您在构建时使用了较新的版本,那么在运行时也需要使用该较新的版本。 (2认同)
  • 当心 VS2013 和 .Net 4.5.1 [AutoGenerateBindingRedirects](https://msdn.microsoft.com/en-us/library/2fc472t2(v=vs.110).aspx) 它们可能会将 dll 绑定重定向到较新的版本即使您告诉它使用特定版本 (2认同)
  • @HansPassant 我认为当程序集没有强名称签名时,CLR 不会考虑`[AssemblyVersion]`。 (2认同)