C#开发中是否有优雅方案实现插件接口与实现的分离?
C# 无编译期依赖插件实现方案说明
- 拆分「仅包含公共接口的共享程序集」+「插件具体实现程序集」本身就是.NET生态下插件开发的标准最佳实践,符合依赖倒置原则,没有必要为了追求形式上的“优雅”刻意规避该设计,你可以在该设计基础上优化加载逻辑,降低开发成本。
- 运行时动态加载可直接使用.NET官方提供的
AssemblyLoadContext(适用于.NET Core 3.0+ / .NET 5+ 及更高版本)实现,完全不需要主程序在编译期引入插件实现项目的依赖:- 单独创建类库项目,仅存放所有插件需要实现的公共接口(如
IPlugin),主程序和所有插件实现项目仅引用该接口项目即可,不需要互相引用 - 主程序运行时扫描指定目录的插件DLL,动态加载并筛选实现了目标接口的类型完成实例化,参考代码如下:
// 共享接口程序集中的定义 public interface IPlugin { string PluginName { get; } void Run(); } // 主程序加载逻辑 public List<IPlugin> LoadPlugins(string pluginDir) { var result = new List<IPlugin>(); var dllFiles = Directory.GetFiles(pluginDir, "*.dll"); foreach (var dllPath in dllFiles) { // 独立加载上下文支持插件隔离、热卸载,避免和主程序类型冲突 var loadContext = new AssemblyLoadContext($"Plugin_{Path.GetFileNameWithoutExtension(dllPath)}", isCollectible: true); try { var assembly = loadContext.LoadFromAssemblyPath(dllPath); // 筛选符合要求的插件类型 var pluginTypes = assembly.GetTypes() .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract && t.IsPublic); foreach (var type in pluginTypes) { var instance = (IPlugin)Activator.CreateInstance(type); result.Add(instance); } } catch { // 忽略无效的非插件DLL continue; } } return result; } - 单独创建类库项目,仅存放所有插件需要实现的公共接口(如
- 如果需要自动处理插件依赖、版本隔离、自动注入等能力,可直接使用官方轻量托管扩展框架
System.Composition,依然只需要依赖共享接口程序集,无需编译期引用插件实现项目:插件实现类添加[Export(typeof(IPlugin))]特性标记,主程序通过CompositionHost批量扫描目录即可完成所有插件的加载,不需要手动写反射筛选逻辑。 - 若坚持不使用独立共享接口程序集,唯一可行的替代方案是使用
dynamic动态类型接收插件实例,但该方案会完全丢失编译时类型检查,运行时类型不兼容风险极高,非常不推荐,优先级远低于拆分共享接口的方案。
内容的提问来源于stack exchange,提问作者Stanislav Koncebovski
相关产品推荐
相关产品推荐

