将外部程序集加载到新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
相关产品推荐
相关产品推荐

