问题概述
在 QT 应用中通过 CLR 调用 C# 的 NPOI 库处理 Excel 文件时,遇到程序集版本冲突问题。具体表现为:
- ❌ QT CLR 调用:报 System.Memory、System.Buffers 等程序集版本不匹配错误
错误信息示例:
NPOI.OpenXml4Net.Exceptions.InvalidFormatException: 未能加载文件或程序集“System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。
根本原因分析
1.版本不一致性
- NPOI 编译时依赖:System.Memory v4.0.1.1、System.Buffers v4.0.2.0
- 本地实际安装:System.Memory v4.0.1.2、System.Buffers v4.5.1.0
- 绑定重定向失效
2.配置文件加载机制不同
C# 直接运行:
<!-- 自动加载: App.config --><configuration> <runtime> <!-- 绑定重定向有效 --> <dependentAssembly> <assemblyIdentityname="System.Memory"publicKeyToken="cc7b13ffcd2ddd51"culture="neutral" /> <bindingRedirectoldVersion="0.0.0.0-4.0.1.2"newVersion="4.0.1.2" /> </dependentAssembly> </runtime></configuration>
QT CLR 调用:
<!-- QT 不加载 .config 文件 --><!-- 或者加载错误的 .config 文件 -->
3.实际原因分析
// C# 程序启动时:// 1. 读取exe.config// 2. 应用绑定重定向// 3. System.Memory 4.0.1.1 → 4.0.1.2 ✓// QT CLR 调用时:// 1. 可能没有配置文件// 2. 或者加载 QT 的配置,而不是 C# DLL 的配置// 3. 绑定重定向不生效 ✗// 4. 找不到 System.Memory 4.0.1.1
️解决方案:
在 C# 代码中强制绑定重定向
新建一个AssemblyBindingManager类
public class AssemblyBindingManager{ private static bool _initialized = false; publicstaticvoidInitializeBindingRedirects() { if (_initialized) return; // 强制应用绑定重定向,不依赖配置文件 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var requestedAssembly = new AssemblyName(args.Name); if (requestedAssembly.Name == "System.Memory" &&requestedAssembly.Version == new Version(4, 0, 1, 1)) { //重定向: System.Memory {requestedAssembly.Version} → 4.0.1.2 return Assembly.Load("System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"); } if (requestedAssembly.Name == "System.Buffers" && requestedAssembly.Version == new Version(4, 0, 2, 0)) { //重定向: System.Buffers {requestedAssembly.Version} → 4.0.3.0 return Assembly.Load("System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"); } // System.Runtime.CompilerServices.Unsafe 4.0.4.1 → 6.0.0.0 if (requestedAssembly.Name == "System.Runtime.CompilerServices.Unsafe" &&requestedAssembly.Version == new Version(4, 0, 4, 1)) { //重定向: System.Runtime.CompilerServices.Unsafe {requestedAssembly.Version} → 6.0.0.0 return Assembly.Load("System.Runtime.CompilerServices.Unsafe,Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); } return null; }; _initialized = true; PreloadAssemblies(); } privatestaticvoidPreloadAssemblies() { try { // 预加载,确保程序集可用 var memory = Assembly.Load("System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"); var buffers = Assembly.Load("System.Buffers, Version=4.5.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"); var unsafeAssembly = Assembly.Load("System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); Console.WriteLine("关键程序集预加载成功"); } catch (Exception ex) { Console.WriteLine($"预加载失败: {ex.Message}"); } }}
在ExcelHelper中调用
publicExcelHelper(){ AssemblyBindingManager.InitializeBindingRedirects(); excelOperateDictionary = new Dictionary<int, ExcelOperateObject>();}