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

将外部程序集加载到新AppDomain并仅通过基类类型创建实例实现插件系统

问题解答

第一个问题:能否实现该需求?

完全可以,这是.NET Framework下插件系统实现隔离加载的经典方案,你提到的Remoting其实是这个方案的底层支撑,跨AppDomain访问对象的通信逻辑.NET已经内置处理,不需要你额外做Remoting的服务注册、通道配置等操作。具体实现注意两个核心要点:

  • 你在类库A中定义的抽象基类必须继承MarshalByRefObject,跨AppDomain访问对象时需要通过这个基类生成远程代理,否则会触发类型序列化异常,无法正常调用实例方法
  • 实例创建不要用当前域的Activator.CreateInstance,而是调用新AppDomain的CreateInstanceFromAndUnwrap方法,直接返回基类类型的代理对象,示例代码逻辑如下:
// 创建隔离的AppDomain
var pluginDomain = AppDomain.CreateDomain("PluginDomain");
// 加载插件程序集并创建实例,直接转为基类类型
var pluginInstance = (BaseClass)pluginDomain.CreateInstanceFromAndUnwrap("B.dll", "B中实现类的完整命名空间+类名");
// 后续直接调用基类定义的抽象方法即可
pluginInstance.YourAbstractMethod();

如果不想硬编码实现类的全名,你可以先在新AppDomain中加载B的程序集,反射遍历所有类型筛选出继承自基类的目标类型,再创建实例即可,和你补充的反射查找逻辑一致,仅需调整实例创建的入口为新AppDomain的方法即可。

更优的实现方案

根据你使用的.NET框架版本不同,有更成熟的方案可选,不用自己从零处理程序集加载、类型查找、依赖解析的各种边界问题:

如果你使用.NET Framework

  • 优先使用官方自带的MEF(Managed Extensibility Framework),这是专门为插件系统设计的框架:你只需给类库A的抽象基类加InheritedExport特性,插件B的实现类不需要额外加特性,主程序通过CompositionContainer就能自动扫描所有插件程序集,直接获取所有基类实现的实例,也支持配置插件加载到独立AppDomain实现隔离,卸载插件时直接销毁对应容器或者卸载AppDomain即可,不用自己写反射查找逻辑。
  • 如果坚持自己实现,记得给新AppDomain设置正确的应用程序基路径和私有探测路径,避免插件依赖的第三方库加载失败。

如果你使用.NET Core/.NET 5+

  • 不要使用AppDomain做插件隔离,该版本已经移除了AppDomain的程序集卸载能力,改用官方推荐的AssemblyLoadContext(ALC)实现:每个插件加载到独立的ALC中,不需要了直接调用ALC的Unload()方法即可完全卸载插件所有相关程序集,比AppDomain更轻量性能更好。
  • 可以使用适配.NET Core的新版MEF(NuGet包名System.Composition),同样可以实现自动扫描插件、实例注入的能力,也支持搭配ALC实现隔离加载。

注意避坑

  • 所有插件和主程序引用的公共契约类库A必须版本完全一致,否则会出现类型不匹配的无效转换异常,哪怕类名、命名空间完全相同也会报错,因为是不同程序集加载出来的独立类型。
  • 跨隔离边界(跨AppDomain/跨ALC)传递参数时,尽量使用公共契约定义的类型或者.NET基础类型,不要传递插件内部自定义的非公共类型,避免出现序列化失败或者类型无法解析的问题。

内容的提问来源于stack exchange,提问作者user1062704

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 03:33:02