傳統擴充方式:新增功能 → 修改主專案參考 → 重新編譯部署。MEF(Managed Extensibility Framework) 打破此循環:主程式只定義介面契約,擴充件獨立編譯為 DLL 放入指定目錄,主程式啟動時自動發現、組裝、使用——完全不動主專案一行碼。
IExtBase),雙方依賴抽象而非具體類別。[Export],宣告「我實作了這個契約」。[Import] 標記需求,CompositionContainer 掃描目錄自動注入。// CommExtBase.dll
public interface IExtBase {
void DoTask();
string TaskName { get; }
}
// TaskToa.dll(獨立專案,參考 CommExtBase)
[Export("task1", typeof(IExtBase))]
public class Task_1 : IExtBase {
public void DoTask() => Console.WriteLine("任務1執行。");
public string TaskName => "任務1";
}
[Export("task2", typeof(IExtBase))]
public class Task_2 : IExtBase {
public void DoTask() => Console.WriteLine("任務2執行。");
public string TaskName => "任務2";
}
編譯後將 TaskToa.dll 複製到主程式 bin\Debug 目錄——主專案完全不參考 TaskToa。
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using CommExtBase;
namespace MainApp {
class TestWork {
[Import("task1")] public IExtBase Task1;
[Import("task2")] public IExtBase Task2;
}
class Program {
static void Main() {
// ApplicationCatalog:掃描執行目錄下所有 DLL
var catalog = new ApplicationCatalog();
var container = new CompositionContainer(catalog);
var tw = new TestWork();
container.ComposeParts(tw); // 組裝
Console.WriteLine($"Task1 型別:{tw.Task1.GetType().Name}, Name:{tw.Task1.TaskName}");
tw.Task1.DoTask();
Console.WriteLine($"Task2 型別:{tw.Task2.GetType().Name}, Name:{tw.Task2.TaskName}");
tw.Task2.DoTask();
Console.Read();
}
}
}


ApplicationCatalog:掃描應用程式目錄(含子目錄)所有 .exe/.dll,最適合「外掛資料夾」部署。DirectoryCatalog:指定特定資料夾,支援檔案名稱篩選(如 Plugin.*.dll)。AssemblyCatalog:掃描單一組件,適合單元測試或內建擴充。AggregateCatalog:合併上述多個來源。需要時果斷採用,否則反受其亂。 簡單專案不必引入 MEF。
技術運用講求靈活,無招勝有招。 別為了用 MEF 而把所有類別都變成外掛。
這就是 MEF 入門的全部核心。下一篇將深入 [Export]/[Import] 契約匹配細節與 ImportMany/Lazy 進階用法。