使用Assembly.LoadFrom加载两个程序集却获取相同路径的原因?
这个问题我之前帮不少开发者排查过——你遇到的核心问题是:CLR会根据程序集的完整标识(名称、版本、文化、公钥标记)来区分程序集,如果你的新旧版本DLL只是文件路径不同,但这些标识完全一致,CLR会认为它们是同一个程序集,后续加载会直接复用(或覆盖)已加载的实例,最终导致两个Assembly对象都指向最后加载的那个DLL。
先看一下你的代码:
string Version1_dll = System.Configuration.ConfigurationManager.AppSettings["Version1_dll"];//New_Dll string Version2_dll = System.Configuration.ConfigurationManager.AppSettings["Version2_dll"];//Old Dll Assembly assembly1 = Assembly.LoadFrom(Version1_dll); Assembly assembly2 = Assembly.LoadFrom(Version2_dll);
解决办法分三种,你可以根据场景选择:
1. 用Assembly.LoadFile()替代LoadFrom()
LoadFile()会直接加载指定路径的程序集,不会校验程序集标识,也不会将其加入CLR的默认加载上下文,这样就能同时加载两个标识相同但路径不同的DLL。修改后的代码:
string Version1_dll = System.Configuration.ConfigurationManager.AppSettings["Version1_dll"];//New_Dll string Version2_dll = System.Configuration.ConfigurationManager.AppSettings["Version2_dll"];//Old Dll Assembly assembly1 = Assembly.LoadFile(Version1_dll); Assembly assembly2 = Assembly.LoadFile(Version2_dll);
⚠️ 注意:LoadFile()不会自动解析程序集的依赖项,如果你的DLL有其他依赖,需要手动处理这些依赖的加载路径。
2. 给不同版本DLL设置不同的程序集标识(推荐)
这是最规范的长期解决方案。在编译DLL时,为新旧版本设置不同的版本号(比如新版本设为1.1.0.0,旧版本保留1.0.0.0),或者添加不同的强名称签名,让它们的程序集标识完全区分开。这样Assembly.LoadFrom()就能正确识别两个不同的程序集,不会出现覆盖问题。
3. 用独立的应用程序域(AppDomain)隔离加载
如果你的场景需要完全隔离两个版本DLL的运行环境,可以创建独立的AppDomain来分别加载每个DLL。每个AppDomain有自己的程序集加载上下文,互不干扰。示例代码:
// 创建专门加载旧版本DLL的AppDomain AppDomain oldVersionDomain = AppDomain.CreateDomain("OldVersionDomain"); Assembly assembly2 = oldVersionDomain.Load(AssemblyName.GetAssemblyName(Version2_dll)); // 当前AppDomain加载新版本DLL Assembly assembly1 = Assembly.LoadFrom(Version1_dll); // 使用完毕后记得卸载AppDomain,释放资源 AppDomain.Unload(oldVersionDomain);
这种方式适合需要严格隔离的复杂场景,但跨AppDomain的对象通信需要额外处理(比如使用MarshalByRefObject)。
总结
优先推荐方案2(规范版本管理),这能从根源避免此类问题;如果无法修改DLL的版本信息,方案1是最快的解决方式;方案3适合需要环境隔离的特殊场景。
内容的提问来源于stack exchange,提问作者Praveen

