MEF是.NET的插件化框架,通过Export/Import机制实现组件自动装配。定义IPlugin接口,插件用[Export(typeof(IPlugin))]标记,主程序用[ImportMany]加载插件,DirectoryCatalog扫描目录,CompositionContainer完成组合,支持延迟加载与热更新监控。

插件化开发能让程序在不修改主程序代码的前提下动态加载功能模块,提升系统的可扩展性和维护性。C# 中实现插件化的方式有多种,其中 MEF(Managed Extensibility Framework)是微软官方提供的一种轻量级、声明式的组件组合框架,特别适合构建可扩展的应用程序。
什么是 MEF?
MEF 是 .NET Framework 4.0 引入的一个库,用于创建可扩展的应用程序。它通过“导出”和“导入”的机制,自动发现并加载外部组件(即插件),无需硬编码依赖关系。
核心概念包括:
- Export(导出):标记某个类或方法可以被外部使用。
- Import(导入):声明需要从外部获取某个对象。
- CompositionContainer:负责协调导入与导出,完成对象的装配。
- DirectoryCatalog:从指定目录中扫描程序集,查找带有导出标记的类型。
如何使用 MEF 实现插件化?
下面通过一个简单示例展示 MEF 的基本用法。
第一步:安装 MEF
如果你使用的是 .NET Framework 4.0 及以上版本,MEF 已内置在 System.ComponentModel.Composition 命名空间中。对于 .NET Core/.NET 5+,需通过 NuGet 安装:
Install-Package System.ComponentModel.Composition
第二步:定义公共接口
为了让主程序与插件解耦,先定义一个共享接口。通常放在独立的类库中,供主程序和插件引用。
public interface IPlugin
{
string Name { get; }
void Execute();
}
第三步:编写插件(导出组件)
创建一个类库项目作为插件,引用上面的接口和 MEF 相关命名空间。
[Export(typeof(IPlugin))]
public class HelloPlugin : IPlugin
{
public string Name => "Hello 插件";
public void Execute()
{
Console.WriteLine("HelloPlugin 正在执行!");
}}
这里使用 [Export] 特性将该类标记为可被容器加载的组件。
第四步:主程序中导入并使用插件
在主程序中使用 CompositionContainer 扫描插件目录,自动加载所有符合接口的插件。
class Program
{
[ImportMany] // 导入多个 IPlugin 实例
private IEnumerable> Plugins { get; set; }
static void Main(string[] args)
{
var program = new Program();
program.LoadPlugins();
program.RunPlugins();
}
private void LoadPlugins()
{
// 指定插件存放目录
var catalog = new DirectoryCatalog("./Plugins", "*.dll");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
private void RunPlugins()
{
foreach (var plugin in Plugins)
{
Console.WriteLine($"加载插件:{plugin.Value.Name}");
plugin.Value.Execute();
}
}}
注意:Lazy 表示插件是延迟加载的,只有在真正访问 Value 时才会实例化,有助于提升性能。
插件热更新与目录监控
如果希望程序运行时能自动发现新添加的插件,可以结合文件系统监视器(FileSystemWatcher)定期刷新目录。
var catalog = new DirectoryCatalog("./Plugins", "*.dll");
// 当目录变化时重新扫描
catalog.Changed += (sender, e) =>
{
Console.WriteLine("检测到插件变更,可触发重新加载...");
};
不过 MEF 默认不会自动重新组合,需要手动重建容器或处理刷新逻辑。
常见注意事项
- 确保插件 DLL 放在指定目录(如 ./Plugins),且主程序能访问该路径。
- 插件项目需引用主程序使用的接口程序集,避免类型不匹配。
- 使用
Lazy 避免不必要的对象创建。
- 处理异常:某些插件加载失败不应导致整个程序崩溃,建议对插件调用做 try-catch 包装。
基本上就这些。MEF 让 C# 插件化变得简洁直观,适合中小型扩展系统。虽然现在也有更现代的方案如 AssemblyLoadContext + DI 容器,但 MEF 仍是一个稳定、易上手的选择。










