Assembly.GetExecutingAssembly().GetName().Version 返回编译时固定的 AssemblyVersion,而非文件属性中的版本;真正对应文件“详细信息”中版本的是 FileVersionInfo.GetVersionInfo() 读取的 PE 资源。

用 Assembly.GetExecutingAssembly().GetName().Version 读当前程序集版本
这个是最常用也最容易出错的入口。它返回的是编译时写死在 AssemblyInfo.cs(或项目文件 .csproj 中 Version 属性)里的版本号,不是文件系统里显示的“文件版本”或“产品版本”。很多人以为改了资源里的版本号它就会变,其实不会。
常见错误现象:Version 始终是 1.0.0.0,哪怕你右键文件属性里看到的是 2.3.4.5;或者发布后版本没更新,因为只改了 AssemblyFileVersion 没动 AssemblyVersion。
-
AssemblyVersion控制强命名和运行时绑定,改动需同步更新引用方,否则报FileNotFoundException -
AssemblyFileVersion和AssemblyInformationalVersion只影响文件属性,不影响加载逻辑 - 如果项目用 SDK 风格(
<Project Sdk="Microsoft.NET.Sdk">),版本通常由<Version>2.3.4</Version>控制,它默认同时设AssemblyVersion和AssemblyFileVersion,但可单独覆盖
用 FileVersionInfo.GetVersionInfo() 读磁盘上任意文件的真实版本信息
这才是真正对应 Windows 文件属性页里“详细信息”标签下的“文件版本”“产品版本”的 API。它不依赖程序集元数据,而是解析 PE 文件头 + 资源段,所以能读 exe/dll/甚至某些带版本资源的普通文件。
使用场景:检查已部署的 DLL 是否被替换成旧版;验证安装包里文件版本是否符合预期;做热更新校验。
- 参数必须是绝对路径,传相对路径容易因
CurrentDirectory改变而失败 - 如果目标文件被占用(如正在运行的 EXE),仍可读取,Windows 允许共享读取版本资源
- 返回对象的
FileVersion对应“文件版本”,ProductVersion对应“产品版本”,二者常不同(比如 .NET Runtime 的ProductVersion是8.0.0,FileVersion是8.0.223.61711) - 示例:
var info = FileVersionInfo.GetVersionInfo(@"C:\MyApp\MyApp.exe"); Console.WriteLine(info.FileVersion); // 输出 "2.3.4.5"
为什么 AssemblyName.Version 和文件属性里的版本经常对不上
根本原因是它们来源不同、用途不同、更新时机也不同。混淆这两者是 C# 版本读取问题的绝大多数根源。
-
Assembly.GetName().Version来自 IL 元数据的AssemblyRef记录,编译期确定,运行时不可变 -
FileVersionInfo.FileVersion来自 PE 文件的VS_VERSION_INFO资源,可独立编辑(比如用rc.exe或第三方工具),甚至能在不重编译情况下打补丁 - 在 CI/CD 流程中,如果只改
.csproj的Version但没触发重新编译(比如只改了 Git Tag),实际生成的 DLL 版本还是旧的 - 调试时用
typeof(Program).Assembly.Location获取路径再传给GetVersionInfo,比硬编码路径更可靠
读取第三方 DLL 版本时要注意加载冲突
直接调用 Assembly.LoadFrom(path) 再取 .GetName().Version 看似简单,但极易引发 FileLoadException 或静默加载失败——尤其当该 DLL 依赖其他版本的框架或有强命名冲突时。
这不是你想查版本,结果把整个 AppDomain 搞崩了。
- 优先用
FileVersionInfo.GetVersionInfo(path),它不加载程序集,纯读资源,零副作用 - 如果真要加载(比如还要反射类型),务必用
AssemblyLoadContext.IsDefault判断上下文,并考虑用隔离的AssemblyLoadContext加载 - 注意:
GetVersionInfo对 .NET Core/.NET 5+ 的单文件发布(SingleFile)有效,但对“已提取到临时目录”的场景,得读取实际解压后的文件路径,而非原始 .exe
事情说清了就结束。版本这东西,表面看只是几个数字,背后连着编译流程、资源嵌入、加载机制和部署策略——哪一环松了,拿到的就不是你以为的那个“版本”。


















