[TOC] MEF 簡介 Managed Extensibility Framework 即 MEF 是用於創建輕量、可擴展應用程式的庫。 它讓應用程式開發人員得以發現和使用擴展且無需配置。 它還讓擴展開發人員得以輕鬆地封裝代碼並避免脆弱的緊密依賴性。 MEF 讓擴展不僅可在應用程式內重覆使用,還可 ...
目錄
MEF 簡介
Managed Extensibility Framework 即 MEF 是用於創建輕量、可擴展應用程式的庫。 它讓應用程式開發人員得以發現和使用擴展且無需配置。 它還讓擴展開發人員得以輕鬆地封裝代碼並避免脆弱的緊密依賴性。 MEF 讓擴展不僅可在應用程式內重覆使用,還可以跨程式重覆使用。
在進行傳統的 C/S 端開發,如果項目不是特別複雜,常規的開發模式還是可以應對的。但是一旦場景複雜度提升,一個小小業務功能的修改就需要更新整個客戶端,這個對於開發者來說是不能忍受的。因此微軟為我們引入了 MEF 的開發模式。允許我們將眾多的業務模塊拆分開來設計成獨立的 DLL,然後由客戶端來進行統一載入,這樣就能解決上述我們所說的痛點。
實踐出真知
創建一個高擴張的 MEF 框架涉及的技術點較多。為了方便初學者能較快理解,上手實踐,我這裡主要通過 3 個方面來進行相關敘述。
面向介面編程
如果你還不能理解什麼是面向介面編程的話,那你應該還不能區分抽象類和介面之間的區別。其實在剛開始的時候我也不是很能理解,直到我看到了一句話:抽象類規定了你是什麼,介面規定了你能幹什麼,只要你能理解這句話,那麼你應該就明白什麼是面向介面編程,這種編程方式的好處是統一化了業務的暴露方式,方便外部使用。下麵我們看一個簡單的例子。
public interface IMessage
{
void Send();
}
public class EmailService : IMessage
{
public void Send()
{
Console.WriteLine("Email Send Message");
}
}
public class SMSService : IMessage
{
public void Send()
{
Console.WriteLine("SMS Send Message");
}
}
class Program
{
static void Main(string[] args)
{
IMessage email = new EmailService();
email.Send();
IMessage sms = new SMSService();
sms.Send();
Console.ReadKey();
}
}
上述代碼中,我們創建了一個 IPlugin 的介面,介面定義了一個 ShowPluginName() 方法,然後我們再定義了兩個獨立的類來分別繼承該介面並實現相應的介面函數。在主函數中,我們只需要定義一個介面類型的對象,然後接收一個具體的類型實例,函數就會輸出對應的正確信息。這樣編程的好處就不言而喻了。代碼很簡單,這裡就不過多描述。輸出結果如下圖所示
控制反轉(IOC)
所謂控制反轉,就是將對象初始化的控制權交出去。要實現控制反轉,我們需要有面向介面編程的介面,同樣的,這裡也是展示一個代碼段來敘述。
public interface IMessage
{
void Send();
}
public class EmailService : IMessage
{
public void Send()
{
Console.WriteLine("Email Send Message");
}
}
public class SMSService : IMessage
{
public void Send()
{
Console.WriteLine("SMS Send Message");
}
}
public static class Factory
{
public static EmailService GetEmailService() => new EmailService();
public static SMSService GetSMSService() => new SMSService();
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("DependencyService:");
DependencyService();
Console.WriteLine();
Console.WriteLine("InversionDependencyService:");
InversionDependencyService();
Console.ReadKey();
}
static void DependencyService()
{
EmailService fooEmailService = new EmailService();
fooEmailService.Send();
}
static void InversionDependencyService()
{
IMessage fooMessage = Factory.GetEmailService();
fooMessage.Send();
fooMessage = Factory.GetSMSService();
fooMessage.Send();
}
}
在這個例子中,我們通過工廠模式創建具體的服務,然後供主程式來調用,代碼依然很簡單,分別用傳統創建服務的方式和 控制反轉的方式來進行對比。程式輸出如下
構建入門級 MEF
有了上面兩個知識點做鋪墊,我們可以開始創建一個入門級的 MEF 示常式序。想要在程式中使用 MEF 的話需要引入如下程式集
- System.ComponentModel.Composition
這裡還是以控制台程式來展示。項目結構如下圖所示
- MefSample.Core:核心介面定義在該項目中
- MefSample.EmailService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
- MefSample.SMSService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
- MefSample:主程式,需要引用 MefSample.Core 和 System.ComponentModel.Composition
註意:上述所有項目程式的輸出目錄需要保持一致
MefSample.Core 代碼段
public interface IMessage
{
void Send();
}
MefSample.EmailService 代碼段
[Export(typeof(IMessage))]
public class EmailService: IMessage
{
public void Send()
{
Console.WriteLine("Email Send Message");
}
}
MefSample.SMSService 代碼段
[Export(typeof(IMessage))]
public class SMSService : IMessage
{
public void Send()
{
Console.WriteLine("SMS Send Message");
}
}
MefSample 代碼段
class Program
{
static void Main(string[] args)
{
var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
var catalog = new DirectoryCatalog(dir.FullName, "*.dll");
using (CompositionContainer container = new CompositionContainer(catalog))
{
IEnumerable<IMessage> messages = container.GetExportedValues<IMessage>();
if (messages != null)
{
foreach (var message in messages)
{
message.Send();
}
}
}
Console.ReadKey();
}
}
仔細觀察的話,其實上述代碼還是挺簡單的, 我這裡使用了 DirectoryCatalog 的方式來尋找目標插件,感興趣的朋友可以試試其他方式:AggregateCatalog
、AssemblyCatalog
、DirectoryCatalog
。當然,你也可以自定義。程式輸出結果如下圖所示
好了,程式寫到這裡相信你對 MEF 也多少有些瞭解。我沒有過多的講解抽象理論,而是更多地通過代碼來描述我所想要說的。在下篇文章中,我將會簡單講述一下 MEF 在 WPF 中的入門使用,方便初學者更上一層樓。加油,共勉!