You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:27:40