ChatGPT解决这个技术问题 Extra ChatGPT

AssemblyVersion、AssemblyFileVersion 和 AssemblyInformationalVersion 之间有什么区别?

有三个程序集版本属性。有什么区别?如果我使用 AssemblyVersion 并忽略其余部分可以吗?

MSDN 说:

AssemblyVersion:指定被赋予属性的程序集的版本。

AssemblyFileVersion:指示编译器为 Win32 文件版本资源使用特定版本号。 Win32 文件版本不需要与程序集的版本号相同。

AssemblyInformationalVersion:定义程序集清单的附加版本信息。

这是对 What are the best practices for using Assembly Attributes? 的跟进


R
Remy van Duijkeren

汇编版本

引用您的程序集的其他程序集将在哪里查找。如果此编号发生更改,其他程序集必须更新它们对您程序集的引用!仅当它破坏向后兼容性时才更新此版本。 AssemblyVersion 是必需的。

我使用格式:major.minor(对于非常稳定的代码库来说是major)。这将导致:

[assembly: AssemblyVersion("1.3")]

如果您严格遵循 SemVer,则这意味着您仅在 major 更改时更新,例如 1.0、2.0、3.0 等。

程序集文件版本

用于部署(如安装程序)。您可以为每个部署增加此数字。使用它来标记具有相同 AssemblyVersion 但从不同构建和/或代码生成的程序集。

在 Windows 中,可以在文件属性中查看。

AssemblyFileVersion 是可选的。如果未给出,则使用 AssemblyVersion。

我使用格式:major.minor.patch.build,前三部分遵循 SemVer,最后一部分使用构建服务器的内部版本号(0 表示本地构建)。这将导致:

[assembly: AssemblyFileVersion("1.3.2.42")]

请注意,System.Version 将这些部分命名为 major.minor.build.revision

汇编信息版本

程序集的产品版本。这是您在与客户交谈或在您的网站上显示时使用的版本。此版本可以是字符串,例如“1.0 Release Candidate”。

AssemblyInformationalVersion 是可选的。如果未给出,则使用 AssemblyFileVersion。

我使用格式:major.minor[.patch] [revision as string]。这将导致:

[assembly: AssemblyInformationalVersion("1.3 RC1")]

对于 AssemblyFileVersion,“如果可能,让它由 MSBuild 生成” - 为什么?您只是继续解释了手动控制它的充分理由:)
AssemblyInformationalVersion 格式的警告今天(2013 年 5 月 21 日)在 VS2010 中仍然存在,并且您的链接已失效。
不幸的是,Version Class 定义了 major.minor[.build[.revision]] 而不是 major.minor.revision.build,因此在给定的答案中,如果您使用类属性或 System.Reflection.Assembly.GetExecutingAssembly().GetName().Version 来检测构建号和修订号,那么构建号和修订号将被交换。
@thinkOfaNumber 你对版本类的权利,但这是微软的版本控制方式。我个人认为最后没有内部版本号很奇怪,这就是为什么我只将我的格式作为示例,基于 Semantic Versioning。您可以自由使用 Microsoft 方式或您自己的方式。
需要注意的是,对于AssemblyInformationalVersion,如果省略,则使用AssemblyFileVersion那么 AssemblyVersion 如果两者都被省略。
D
Daniel Fortunov

鉴于目前至少有三种方法可以为您的程序集指定版本,因此在 .NET 中对程序集进行版本控制可能是一个令人困惑的前景。

以下是与版本相关的三个主要程序集属性:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

按照惯例,版本的四个部分被称为主要版本、次要版本、构建和修订。

AssemblyFileVersion 旨在唯一标识单个程序集的构建

通常,您将手动设置 Major 和 Minor AssemblyFileVersion 以反映程序集的版本,然后在每次构建系统编译程序集时增加 Build 和/或 Revision。 AssemblyFileVersion 应该允许您唯一标识程序集的构建,以便您可以将其用作调试任何问题的起点。

在我当前的项目中,我们让构建服务器将源代码控制存储库中的更改列表编号编码到 AssemblyFileVersion 的构建和修订部分中。这允许我们直接从一个程序集映射到它的源代码,用于构建服务器生成的任何程序集(无需在源代码控制中使用标签或分支,或手动保留任何已发布版本的记录)。

此版本号存储在 Win32 版本资源中,可以在查看程序集的 Windows 资源管理器属性页时看到。

CLR 不关心也不检查 AssemblyFileVersion。

AssemblyInformationalVersion 旨在代表整个产品的版本

AssemblyInformationalVersion 旨在允许对整个产品进行连贯的版本控制,该产品可能包含许多独立版本的程序集,可能具有不同的版本控制策略,并且可能由不同的团队开发。

“例如,一个产品的 2.0 版本可能包含多个程序集;其中一个程序集被标记为 1.0 版,因为它是未在同一产品的 1.0 版中发布的新程序集。通常,您设置此版本号的主要和次要部分来表示您的产品的公共版本。然后,每次打包完整产品及其所有组件时,都会增加构建和修订部分。” — Jeffrey Richter,[CLR via C#(第二版)] p。 57

CLR 不关心也不检查 AssemblyInformationalVersion。

AssemblyVersion 是 CLR 关心的唯一版本(但它关心整个 AssemblyVersion)

CLR 使用 AssemblyVersion 绑定到强命名程序集。它存储在已构建程序集的 AssemblyDef 清单元数据表中,以及引用它的任何程序集的 AssemblyRef 表中。

这非常重要,因为这意味着当您引用一个强命名程序集时,您将紧密绑定到该程序集的特定 AssemblyVersion。整个 AssemblyVersion 必须完全匹配才能使绑定成功。例如,如果您在构建时引用了强命名程序集的 1.0.0.0 版本,但在运行时只有该程序集的 1.0.0.1 版本可用,则绑定将失败! (然后您必须使用 Assembly Binding Redirection 解决此问题。)

对整个 AssemblyVersion 是否必须匹配感到困惑。 (是的,它确实。)

关于整个 AssemblyVersion 是否必须完全匹配才能加载程序集存在一些混淆。有些人错误地认为只有 AssemblyVersion 的主要部分和次要部分必须匹配才能使绑定成功。这是一个合理的假设,但它最终是不正确的(从 .NET 3.5 开始),并且为您的 CLR 版本验证这一点很简单。只需执行 this sample code

在我的机器上,第二次组装加载失败,融合日志的最后两行非常清楚地说明了原因:

.NET Framework Version: 2.0.50727.3521
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
Successfully loaded assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
Assembly binding for  failed:
System.IO.FileLoadException: Could not load file or assembly 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, 
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's manifest definition 
does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f'

=== Pre-bind state information ===
LOG: User = Phoenix\Dani
LOG: DisplayName = Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
 (Fully-specified)
LOG: Appbase = [...]
LOG: Initial PrivatePath = NULL
Calling assembly : AssemblyBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Post-policy reference: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
LOG: Attempting download of new URL [...].
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

我认为这种混乱的根源可能是因为微软最初打算对完整 AssemblyVersion 的这种严格匹配更宽松一点,只匹配主要和次要版本部分:

“加载程序集时,CLR 将自动查找与所请求程序集的主要/次要版本匹配的最新安装的服务版本。” — Jeffrey Richter,[CLR via C#(第二版)] p。 56

这是 1.0 CLR 的 Beta 1 中的行为,但是此功能在 1.0 版本之前被删除,并且没有设法在 .NET 2.0 中重新出现:

“注意:我刚刚描述了你应该如何看待版本号。不幸的是,CLR 不以这种方式处理版本号。 [在 .NET 2.0 中],CLR 将版本号视为不透明值,如果程序集依赖于另一个程序集的 1.2.3.4 版本,则 CLR 尝试仅加载 1.2.3.4 版本(除非绑定重定向到位)。但是,Microsoft 计划在未来版本中更改 CLR 的加载程序,以便它为给定的主要/次要版本的程序集加载最新的构建/修订。例如,在 CLR 的未来版本中,如果加载程序试图查找程序集的 1.2.3.4 版本并且版本 1.2.5.0 存在,则加载程序会自动选择最新的服务版本。这对 CLR 的加载器来说将是一个非常受欢迎的变化——我等不及了。” — Jeffrey Richter,[CLR via C#(第二版)] p。 164(重点是我的)

由于此更改仍未实施,我认为可以肯定地假设 Microsoft 已在此意图上回溯,现在更改此内容可能为时已晚。我试图在网上搜索以了解这些计划发生了什么,但我找不到任何答案。我仍然想深入了解它。

所以我给杰夫·里希特发了电子邮件,直接问他——我想如果有人知道发生了什么,那就是他。

他在 12 小时内回复,同样是在星期六早上,并澄清说 .NET 1.0 Beta 1 加载程序确实实现了这种“自动前滚”机制来获取程序集的最新可用构建和修订,但这种行为是在 .NET 1.0 发布之前恢复。后来它打算重振它,但在 CLR 2.0 发布之前它没有实现。然后是 Silverlight,它优先考虑 CLR 团队,所以这个功能被进一步延迟。与此同时,在 CLR 1.0 Beta 1 时代周围的大多数人都已经继续前进,因此尽管已经投入了所有艰苦的工作,但它不太可能看到曙光。

当前的行为似乎将继续存在。

从我与 Jeff 的讨论中还值得注意的是,AssemblyFileVersion 仅在删除“自动前滚”机制后才添加 - 因为在 1.0 Beta 1 之后,对 AssemblyVersion 的任何更改对您的客户来说都是一个重大更改,然后无处可以安全地存储您的内部版本号。 AssemblyFileVersion 是安全的避风港,因为 CLR 永远不会自动检查它。也许这样更清楚,有两个不同的版本号,具有不同的含义,而不是试图在 AssemblyVersion 的主要/次要(破坏)和构建/修订(非破坏)部分之间进行分离。

底线:仔细考虑何时更改您的 AssemblyVersion

寓意是,如果您要交付其他开发人员将要引用的程序集,则需要非常小心何时更改(和不)更改这些程序集的 AssemblyVersion。对 AssemblyVersion 的任何更改都意味着应用程序开发人员要么必须针对新版本重新编译(以更新那些 AssemblyRef 条目),要么使用程序集绑定重定向来手动覆盖绑定。

不要为旨在向后兼容的服务版本更改 AssemblyVersion。

请更改您知道有重大更改的版本的 AssemblyVersion。

再看一下 mscorlib 上的版本属性:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

请注意,AssemblyFileVersion 包含所有有趣的服务信息(它是该版本的 Revision 部分,告诉您您正在使用哪个 Service Pack),同时 AssemblyVersion 固定在一个无聊的旧 2.0.0.0。对 AssemblyVersion 的任何更改都会强制每个引用 mscorlib.dll 的 .NET 应用程序针对新版本重新编译!


很好的答案。我认为您提出的最重要的一点——以及 MS 应该明确推荐的内容——是当且仅当新版本破坏了向后兼容性时才对 AssemblyVersion 进行更改。
我反复问自己的一个问题是,我什么时候应该更改这些版本号,您在 AssemblyVersion 上的要点清楚地说明了这一点,整个答案读起来很有趣。
您的答案似乎不再适用于 .NET 5(很可能也适用于 .NET 6 及更高版本,也可能是以前版本的 .NET Core)。我创建了一个带有 1.2.3.4 版和强名称的 C# 控制台应用程序。该应用程序引用了一个版本为 3.4.5.6 和强名称的库。如果 lib 版本低于 3.4.5.6(例如 3.4.5.5、3.4.4.6、3.3.5.6),应用程序将无法启动,这是有道理的。但如果 lib 版本等于或高于用于创建应用程序的版本(等于:3.4.5.6;高于:3.4.5.7、3.4.6.6、3.5.5.6、4.4.5.6),它会成功运行。
G
Grant Palin

AssemblyVersion 几乎保留在 .NET 内部,而 AssemblyFileVersion 是 Windows 所看到的。如果您转到位于目录中的程序集的属性并切换到版本选项卡,您将在顶部看到 AssemblyFileVersion。如果您按版本对文件进行排序,这就是资源管理器所使用的。

AssemblyInformationalVersion 映射到“产品版本”,是纯粹的“人工使用”。

AssemblyVersion 肯定是最重要的,但我也不会跳过 AssemblyFileVersion。如果您不提供 AssemblyInformationalVersion,编译器会通过剥离版本号的“修订”部分并保留 major.minor.build 来为您添加它。


D
Dejan

当您通过 Windows 资源管理器通过查看文件属性查看文件的“版本”信息时,会显示 AssemblyInformationalVersionAssemblyFileVersion。这些属性实际上被编译到由编译器创建的 VERSION_INFO 资源中。

AssemblyInformationalVersion 是“产品版本”值。 AssemblyFileVersion 是“文件版本”值。

AssemblyVersion 特定于 .NET 程序集,由 .NET 程序集加载器用于了解在运行时加载/绑定哪个版本的程序集。

其中,.NET 绝对需要的唯一一个是 AssemblyVersion 属性。不幸的是,当它不加选择地更改时,它也可能导致大多数问题,特别是如果您对程序集进行强命名。


K
KCD

为了使这个问题保持最新,值得强调的是,NuGet 使用 AssemblyInformationalVersion 并反映 包版本,包括任何预发布后缀。

例如,使用 asp.net 核心 dotnet-cli 打包的 AssemblyVersion 为 1.0.3.*

dotnet pack --version-suffix ci-7 src/MyProject

生成一个版本为 1.0.3-ci-7 的包,您可以使用以下方法通过反射进行检查:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);

w
wonea

值得注意的是其他一些事情:

如生成的程序集文件的 Windows 资源管理器属性对话框中所示,有两个地方称为“文件版本”。对话框标题中显示的是 AssemblyVersion,而不是 AssemblyFileVersion。在其他版本信息部分,还有另一个元素称为“文件版本”。在这里您可以看到作为 AssemblyFileVersion 输入的内容。 AssemblyFileVersion 只是纯文本。它不必符合 AssemblyVersion 所做的编号方案限制(例如, < 65K)。如果您愿意,它可以是 3.2..。您的构建系统将必须填写令牌。此外,它不受 AssemblyVersion 的通配符替换。如果您在 AssemblyInfo.cs 中只有一个值“3.0.1.*”,那么这正是其他版本信息->文件版本元素中将显示的内容。不过,我不知道使用数字文件版本号以外的其他内容对安装程序的影响。


l
linquize

当程序集的 AssemblyVersion 更改时,如果它具有强名称,则需要重新编译引用程序集,否则程序集不会加载!如果它没有强名称,如果没有显式添加到项目文件中,则在构建时不会将其复制到输出目录,因此您可能会错过依赖程序集,尤其是在清理输出目录之后。


这很有趣!您能否详细说明“不会被复制到输出目录”部分?也许是定义此行为的链接。我不明白为什么有时会复制一些间接依赖项,但并非总是如此。这必须与它100%相关。