用户真正认得的版本号(如2.1.0-rc.2)需通过Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion获取,它来自AssemblyInformationalVersion属性而非Version;ProductVersion则来自PE资源节,更适用于系统集成场景。

Assembly.GetExecutingAssembly().GetName().Version 返回的是编译时写死的四段数字(如 1.2.3.0),它**不是**用户在“属性→详细信息”里看到的那个带后缀的版本(比如 2.1.0-beta),也不含编译时间。真正在关于窗口里该显示的,是 AssemblyInformationalVersion,配合手动注入的编译时间戳才完整。
怎么拿到用户真正认得的版本号(比如 2.1.0-rc.2)
这个字符串存在 AssemblyInformationalVersionAttribute 里,不是 Version 属性:
-
Assembly.GetExecutingAssembly().GetCustomAttribute是唯一可靠路径()?.InformationalVersion - 它默认等于
(SDK 风格项目),但可被显式覆盖:1.2.3 2.1.0-rc.2 - 如果没设,返回
null,别直接 .ToString()——容易空引用 - Windows 资源管理器“详细信息”页、“安装包说明”里写的,全靠它
为什么 FileVersionInfo.GetVersionInfo(...).ProductVersion 更常用
因为它是 PE 文件资源里的真实字段,能被 Windows Shell、安装工具、CI/CD 流水线直接读取,且支持独立更新(不用重编译):
-
FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion返回的就是右键→属性→详细信息→产品版本那一栏 - 它和
AssemblyInformationalVersion值常一致,但来源不同:前者来自 VS_VERSION_INFO 资源节,后者来自程序集元数据 - 若你用 CI 打包(如 GitHub Actions),通常会用
dotnet build /p:FileVersion=2.1.0.$(BUILD_NUMBER)注入,这时ProductVersion比InformationalVersion更贴近发布流水线语义 - 注意:
Location可能为空(比如在单元测试上下文或某些 AOT 场景),要加 null 检查
如何把编译时间塞进关于窗口
MSBuild 不自带编译时间,但可以用 $(DateTime) 或 $(Date) 在构建时生成常量:
- 在
.csproj里加:<propertygroup><defineconstants>$(DefineConstants);BUILD_DATE="$(Date)"</defineconstants></propertygroup>
- 代码里用:
const string buildDate = "BUILD_DATE"; // 实际要用预处理器指令展开,或者改用 MSBuild 注入的 AssemblyMetadataAttribute
- 更稳的做法是用
AssemblyMetadataAttribute:<target name="InjectBuildTime" beforetargets="CoreCompile"><itemgroup><assemblymetadata include="BuildTime" value="$([System.DateTime]::Now.ToString(" yyyy-mm-dd hh:mm:ss></assemblymetadata></itemgroup></target>然后读:Assembly.GetExecutingAssembly().GetCustomAttribute("BuildTime")?.Value - 别用
DateTime.Now运行时取——它返回的是启动时间,不是编译时间
关于窗口里到底该显示哪个版本字段
没有标准答案,但有事实约束:
- 用户认知层面:
AssemblyInformationalVersion最匹配(带-beta、-dev后缀,符合发布说明习惯) - 系统集成层面:
ProductVersion更可靠(Windows Installer、PowerShellGet-AppxPackage、SCCM 都认它) - 绑定与加载逻辑层:
Assembly.GetName().Version完全无关——它只影响 GAC 和强命名解析,不该出现在 UI 里 - 如果你做 ClickOnce,还得额外读
ApplicationDeployment.CurrentDeployment.CurrentVersion,它可能和编译时版本不一致
真正容易被忽略的是:这三个版本字段(Version、FileVersion、InformationalVersion)在 SDK 风格项目中由不同 MSBuild 属性控制,改一个不等于其他两个自动同步。发布前务必用 ildasm 或 dotnet dump 验证最终程序集元数据是否符合预期。










