.NET Framework子插件调用Assembly.GetExportedTypes()报错求助
.NET插件中子插件加载的问题分析与解决方案
核心问题原因
1. 依赖程序集找不到的问题
你的主插件是被第三方应用通过Assembly.Load()从非应用目录加载的,此时主插件程序集处于非默认加载上下文中。当你加载子插件时,CLR会默认从应用目录、GAC、配置文件指定的路径去查找子插件依赖的ISubPlugin所在程序集,不会识别已经加载到非默认上下文的主插件,因此抛出找不到程序集的错误。
2. 类型比较不成立的问题
当你把主插件DLL放到应用目录后,子插件加载时,CLR会从应用目录重新加载一份主插件程序集,导致内存中有两个完全相同但来自不同加载实例的主插件程序集。此时:
typeof(ISubPlugin)来自第三方应用最初加载的主插件- 子插件里实现的
ISubPlugin接口来自应用目录加载的主插件副本
.NET中,类型的唯一性由类型全名+所属程序集实例共同决定,所以这两个ISubPlugin会被视为完全不同的类型。调试器只显示类型名称,所以看起来条件为true,但实际运行时比较不成立。
解决方案
方案1:注册程序集解析事件 + 正确的类型匹配逻辑
在主插件初始化时,注册AppDomain.AssemblyResolve事件,当CLR找不到子插件依赖的主插件时,直接返回已经加载的主插件实例;同时修改类型比较逻辑,同时匹配类型全名和所属程序集。
// 主插件初始化时注册解析事件(确保只注册一次,避免重复注册) AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var requestedAsmName = new AssemblyName(args.Name); // 检查是否是当前主插件程序集 if (requestedAsmName.FullName == typeof(ISubPlugin).Assembly.FullName) { return typeof(ISubPlugin).Assembly; } return null; }; // 加载子插件(用LoadFrom可以直接从指定路径加载) var subAsm = Assembly.LoadFrom(@"C:\...\CallbackPluginTest.dll"); foreach (var type in subAsm.GetExportedTypes()) { // 遍历接口,同时匹配类型全名和所属程序集 foreach (var iface in type.GetInterfaces()) { if (iface.FullName == typeof(ISubPlugin).FullName && iface.Assembly == typeof(ISubPlugin).Assembly) { var subPlugin = (ISubPlugin)Activator.CreateInstance(type); subPlugin.Init(); // 注意:你代码里接口定义的是Init(),之前写的InitPlugin是笔误 break; } } }
方案2:使用Assembly.Load加载子插件并指定依赖
如果你坚持用Assembly.Load,可以先获取子插件的程序集名称,再加载,同时依赖AssemblyResolve事件兜底:
// 先注册解析事件(同方案1) AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var requestedAsmName = new AssemblyName(args.Name); if (requestedAsmName.FullName == typeof(ISubPlugin).Assembly.FullName) { return typeof(ISubPlugin).Assembly; } return null; }; // 获取子插件的程序集名称 var subAsmName = AssemblyName.GetAssemblyName(@"C:\...\CallbackPluginTest.dll"); // 加载子插件 var subAsm = Assembly.Load(subAsmName); // 后续类型匹配逻辑同方案1
关键注意事项
- 禁止重复加载同一程序集:不要把主插件DLL放到应用目录,否则必然导致程序集重复加载,引发类型标识冲突。
- 类型比较要严谨:永远不要只通过类型名称判断类型是否相同,必须同时校验所属程序集。
- 接口方法名要一致:你的代码里接口定义的是
Init(),但调用时写的是InitPlugin(),这会导致运行时错误,必须修正为统一的方法名。
内容的提问来源于stack exchange,提问作者Arkadiusz JotEmI Nowik
相关产品推荐
相关产品推荐

