程序集引用的“特定版本”属性如何在Visual Studio中起作用?
今天,我详细了解了Visual Studio 2010中程序集引用的“特定版本”属性。经过几次有意想不到的结果的实验之后,我开始尽可能多地了解该属性的工作原理。 即使如此,在我看来,没有所有的答案,所以这里是我自我回答这个问题的尝试:
程序集引用的“特定版本”属性如何在Visual Studio中起作用?
这是一个编译时的属性!
要知道的最重要的事情之一是“特定版本”是一个在编译时生效,而不是在运行时生效的属性。
这是什么一回事呢?
在构build项目时,需要parsing项目的程序集引用,以查找构build系统应该使用的物理程序集。 如果执行“特定版本”检查(请参阅“什么时候是”特定版本“选项”部分),这会影响程序集parsing过程的结果:
- 构build系统find可能使用的物理组件
- 构build系统将物理组件的版本与存储在.csproj文件中的程序集版本进行比较,以获取组件的参考
- 如果两个组件版本完全相同,则parsing过程成功,并且find的物理组件用于构build
- 如果两个组件版本不匹配,则会丢弃物理组件,并通过查找下一个潜在组件来继续解决过程
- 如果没有更多的潜在物理组件可以find,解决过程失败。 这会导致编译器警告(警告MSB3245),告诉您无法parsing引用。
- 有趣的是, 构build然后继续! 如果代码没有对程序集的实际引用,则构build成功(使用前面提到的警告)。 如果代码具有引用,那么构build将失败,并显示错误,看起来好像代码使用未知types或名称空间。 构build真正失败的唯一迹象是警告MSB3245。
订单在哪个组件被解决
程序集parsing过程定位潜在程序集的顺序似乎是这样的:
- .csproj文件中由
<HintPath>
元素引用的程序集 - 项目输出path
- GAC
请注意,如果GAC中存在多个版本的程序集,则parsing过程将首先尝试parsing为最高版本的程序集。 只有在没有进行“特定版本”检查时,这一点才是重要的。
何时检查“特定版本”?
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”。 这可能是我做了testing的Visual Studio 2010的怪癖。
当您在Visual Studio UI中检查程序集引用的属性(select引用并按F4)时,您看到的“特定版本”属性的值将告诉您Visual Studio是否要执行“特定版本”检查。 在情况6中,UI将显示“真”,但是<SpecificVersion>
元素不存在于.csproj文件中。
“复制本地”的副作用
如果“复制本地”属性设置为“True”,但由于“特定版本”检查而导致程序集parsing过程失败,则不会复制程序集。
参考资料
- 你需要知道在VS2005中引用程序集 (blogs.msdn.com文章)
- .NET 2.0中用于assembly和版本控制的新增function (codemag.com文章重现了上面的MSDN文章,直到措辞,但包含一些截图和关于程序集版本的附加信息)
当您添加一个引用时,Visual Studio会在项目文件中logging程序集的[AssemblyVersion]。 这个很重要。 如果你说一年后创build一个错误修正,那么你要确保使用完全相同版本的参考来重build项目,这是一个真正的插入。 如果引用程序集已更改,则会出现错误。
但是这并不总是可取的。 一些程序员让程序集版本自动增加,每重build一次就生成一个新版本。 尽pipe程序集的公共接口从未改变过。 有些configuration他们的项目通过使用Nuget获取库,让它自动更新库时,有一个新的版本可用。 他们希望将特定版本属性设置为False来抑制编译错误。
了解其后果非常重要,您需要重新部署整个程序以避免事故。 运行时版本不匹配会导致程序崩溃,只能使用.config文件中的<bindingRedirect>
进行压缩,这是有风险的。