最直接可靠的方式是调用 fileversioninfo.getversioninfo,它解析pe文件中嵌入的版本资源,读取fileversion和productversion字符串,二者可能不同;若需assemblyversion则须加载程序集获取。

用 FileVersionInfo.GetVersionInfo 读取文件版本信息
最直接可靠的方式是调用 FileVersionInfo.GetVersionInfo,它能解析 Windows PE 文件(.exe、.dll)中嵌入的版本资源,不依赖文件名或扩展名,也不要求程序正在运行。
注意:该方法读取的是文件的 文件版本(File Version),不是程序集版本(Assembly Version),二者可能不同。
- 传入完整路径,如
"C:\MyApp\app.exe";相对路径需确保当前工作目录正确 - 若文件无版本资源(如未在项目属性中设置“程序集信息”或未嵌入版本块),会返回默认值(如 0.0.0.0)且不抛异常
- 支持 .NET Framework 和 .NET Core / .NET 5+,但 .NET Core 3.1+ 中需引用
System.Diagnostics.FileVersionInfo命名空间(已内置,无需额外 NuGet)
FileVersionInfo.FileVersion 和 ProductVersion 的区别
同一个文件里常有两个关键字符串版本字段:FileVersion(文件版本)和 ProductVersion(产品版本),它们在 Visual Studio 的“程序集信息”对话框中分别对应“文件版本”和“产品版本”输入框。
常见误区是只读 FileVersion,但有些发布流程(如 MSBuild 自动递增)实际更新的是 ProductVersion,而 FileVersion 被固定为 1.0.0.0。
-
fileVersionInfo.FileVersion→ 对应VS_VERSIONINFO.dwFileVersionMS/dwFileVersionLS -
fileVersionInfo.ProductVersion→ 对应VS_VERSIONINFO.dwProductVersionMS/dwProductVersionLS - 两者都是字符串形式(如
"2.1.3.0"),不是Version类型,需手动Version.Parse()才能比较
读取程序集版本(AssemblyVersion)要换方式
如果你真正想获取的是 C# 编译时写死的 [assembly: AssemblyVersion("1.2.3.4")],那 FileVersionInfo 不管用——它读不到 IL 元数据,只能读资源段。
此时必须加载程序集(注意:会触发 JIT 加载,有副作用),再查 AssemblyName.Version:
try
{
var asm = Assembly.LoadFrom(@"C:MyApplib.dll");
var version = asm.GetName().Version; // 这才是 AssemblyVersion
}
catch (BadImageFormatException)
{
// 非托管 DLL、架构不匹配(x86/x64)、.NET 版本不兼容时抛此异常
}-
Assembly.LoadFrom会执行静态构造函数、触发类型初始化,慎用于生产环境读取第三方 DLL - 若只需元数据不执行代码,可用
AssemblyLoadContext.Default.LoadFromAssemblyPath(.NET 5+)或Assembly.ReflectionOnlyLoadFrom(旧版,仅限检查,不能调用) - 对于当前正在运行的程序集,直接用
typeof(Program).Assembly.GetName().Version更安全
常见错误:路径不存在、权限不足、UAC 虚拟化干扰
调用 FileVersionInfo.GetVersionInfo 时突然报 FileNotFoundException 或返回空版本,大概率不是代码问题,而是路径或权限卡点。
- 检查路径是否含中文、空格、特殊符号;用
Path.GetFullPath规范化后再传入 - Windows 应用商店应用(UWP)或受限制沙盒中无法访问任意磁盘路径,会静默失败
- 32 位进程尝试读取
C:Program Files下的 64 位程序时,可能被文件系统重定向到Program Files (x86),或因 UAC 虚拟化把路径映射到用户配置目录 - 某些杀毒软件或 EDR 会 hook 文件读取 API,导致
GetVersionInfo返回空或异常——可先用File.Exists确认文件可访问
版本信息本身不加密也不校验,读出来就是资源节里存的字符串。真要防篡改,得靠签名验证(Assembly.GetName().GetPublicKeyToken() 或 Authenticode)。











