Managed Extensibility Framework(MEF)是 .NET 平台上一套強大的擴充性管理框架,整合了依賴注入(DI)與 Duck Typing 等特性。它讓開發人員能以最小代碼變動擴充應用程式:開發階段定義擴充點,擴充人員即可透過這些點與主程式互動,且雙方不產生直接依賴,甚至可跨多個專案共用擴充元件。
首先看一個簡單的主程式,直接輸出字串:
// Author: TerryLee 2008.8.30
// URL: https://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Console.WriteLine("This is a simple string.");
}
若此字串未來可能變動、來源不固定,便可視為一個擴充點。使用 MEF 重構為「提供者」與「消費者」兩部分:
// Author: TerryLee 2008.8.30
// URL: https://www.cnblogs.com/Terrylee
public class WeekStringProvider
{
[Export("Caption")]
public String OutputTitle
{
get { return "星期六"; }
}
}
[Export("Caption")] 標記此屬性為可被發現的輸出,契約名稱為 "Caption"。同一類別可定義多個 Export,也可改用型別作為契約。
// Author: TerryLee 2008.8.30
// URL: https://www.cnblogs.com/Terrylee
public class Client
{
[Import("Caption")]
public String OutputTitle { get; set; }
}
[Import("Caption")] 聲明需要契約名稱為 "Caption" 的字串。
// Author: TerryLee 2008.8.30
// URL: https://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Client client = new Client();
CompositionContainer container = new CompositionContainer();
container.AddComponent<Client>(client);
container.AddComponent<WeekStringProvider>(new WeekStringProvider());
container.Bind();
Console.WriteLine(client.OutputTitle);
}

只需替換註冊的元件,即可改變行為,無須修改主程式邏輯:
public class DateStringProvider
{
[Export("Caption")]
public String OutputTitle
{
get { return DateTime.Now.ToLongDateString(); }
}
}
static void Main(string[] args)
{
Client client = new Client();
CompositionContainer container = new CompositionContainer();
container.AddComponent<Client>(client);
container.AddComponent<DateStringProvider>(new DateStringProvider());
container.Bind();
Console.WriteLine(client.OutputTitle);
}

除了字串契約,MEF 支援型別契約。定義介面 IStringProvider,提供者實作介面並標記 [Export(typeof(IStringProvider))],消費者以 [Import(typeof(IStringProvider))] 引入,效果相同。
Duck Typing 更進一步:輸入端要求 ICalculator,擴充端可實作不同介面 IMyCalculator,只要雙方以相同 ContractType 標記,即可自動匹配。這意味著擴充元件完全不需參考主程式組件,實現真正的鬆散耦合。
[ContractType("TerryLeeCalculatro")]
public interface ICalculator { int Execute(int x, int y); }
[Export(typeof(ICalculator))]
public class SubCalculator : ICalculator { public int Execute(int x, int y) => x - y; }
[ContractType("TerryLeeCalculatro")]
public interface IMyCalculator { int Execute(int x, int y); }
[Export(typeof(IMyCalculator))]
public class AddCalculator : IMyCalculator { public int Execute(int x, int y) => x + y; }
透過 DirectoryWatchingComponentCatalog 監視指定資料夾(如 Extensions),主程式無須硬編碼註冊,只要將擴充組件放入目錄即自動載入:
static void Main(string[] args)
{
User user = new User();
DirectoryWatchingComponentCatalog catalog = new DirectoryWatchingComponentCatalog();
catalog.AddDirectory(@"Extensions");
CompositionContainer container = new CompositionContainer(catalog.Resolver);
container.AddComponent<User>(user);
container.Bind();
Console.WriteLine(user.Role);
Console.ReadLine();
}

MEF 的核心優勢在於 Duck Typing 與 Plug-In 支援,它不只是 DI 容器,更是完整的擴充管理框架。雖當時仍處 CTP 階段,但已展現極大潛力,未來更將支援 Silverlight 應用程式擴充。官方專案頁面:https://code.msdn.microsoft.com/mef。