ILMerge合并后混合程序集AlphaVSS.x64.dll依赖加载失败求助
这个问题我之前也碰到过——核心原因是混合程序集AlphaVSS.x64.dll的元数据里依然保留着对独立AlphaVSS.Common.dll的引用,哪怕你已经把后者合并到主程序集里了。当CLR加载AlphaVSS.x64.dll时,它还是会尝试从磁盘加载AlphaVSS.Common.dll,而不是用你合并到all-in-one.exe里的版本。这里有两种可行的解决办法:
解决方案1:修改AlphaVSS.x64.dll的引用指向主程序集
你可以用.NET反编译工具(比如dnSpy)修改混合程序集的元数据,让它直接引用你的all-in-one.exe里的AlphaVSS.Common类型:
- 用dnSpy打开
AlphaVSS.x64.dll - 在左侧导航栏找到程序集引用,定位到
AlphaVSS.Common - 右键点击该引用,选择“编辑程序集引用”
- 将程序集名称改为你的主程序集名称(也就是
all-in-one.exe的名称),同时确保版本号、公钥令牌(如果有)和主程序集完全匹配 - 保存修改后的
AlphaVSS.x64.dll
修改完成后,当AlphaVSS.x64.dll需要AlphaVSS.Common的类型时,就会直接从all-in-one.exe里查找,不会再尝试加载独立的DLL。
解决方案2:优化AssemblyResolve事件直接返回已加载的主程序集
如果你不想修改第三方DLL,只需要调整你的AssemblyResolve事件处理逻辑,当收到AlphaVSS.Common的加载请求时,直接返回已经合并了它的主程序集:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args2) => { Console.WriteLine("Loading " + args2.Name); var requestedAssemblyName = new AssemblyName(args2.Name); // 处理AlphaVSS.x64的加载:从当前程序目录读取(不需要硬编码system32,更灵活) if (requestedAssemblyName.Name.Equals("AlphaVSS.x64", StringComparison.OrdinalIgnoreCase)) { string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlphaVSS.x64.dll"); if (File.Exists(path)) { return Assembly.LoadFrom(path); } } // 处理AlphaVSS.Common的请求:直接返回主程序集(因为它已经被合并进来了) else if (requestedAssemblyName.Name.Equals("AlphaVSS.Common", StringComparison.OrdinalIgnoreCase)) { return Assembly.GetExecutingAssembly(); } return null; };
为什么这个方法有效?
当AlphaVSS.x64.dll触发AlphaVSS.Common的加载请求时,CLR会先触发AssemblyResolve事件。我们直接返回当前运行的主程序集(all-in-one.exe),CLR就会在这个程序集里查找需要的AlphaVSS.Common类型,而不会去磁盘寻找独立的DLL文件。
另外注意:ILMerge的时候要确保你使用的参数正确(比如/v4对应.NET 4.x框架),合并后的程序集版本号和原DLL要匹配,避免版本不兼容的问题。
内容的提问来源于stack exchange,提问作者daisy
相关产品推荐
相关产品推荐

