使用MEF方便的扩展
概述
Managed Extensibility Framework(MEF)是.NET平臺(tái)下的一個(gè)擴(kuò)展性管理框架,它是一系列特性的集合,包括依賴注入(DI)以及Duck Typing等。MEF為開發(fā)人員提供了一個(gè)工具,讓我們可以輕松的對(duì)應(yīng)用程序進(jìn)行擴(kuò)展并且對(duì)已有的代碼產(chǎn)生最小的影響,開發(fā)人員在開發(fā)過程中根據(jù)功能要求定義一些擴(kuò)展點(diǎn),之后擴(kuò)展人員就可以使用這些擴(kuò)展點(diǎn)與應(yīng)用程序交互;同時(shí)MEF讓應(yīng)用程序與擴(kuò)展程序之間不產(chǎn)生直接的依賴,這樣也允許在多個(gè)具有同樣的擴(kuò)展需求之間共享擴(kuò)展程序。
本文將介紹一下Managed Extensibility Framework的一些簡單使用。
簡單依賴注入
大家可以去這里http://code.msdn.microsoft.com/mef下載MEF的CTP版本,在下載包里有一些簡單的文檔和示例。下面先來看一個(gè)簡單的示例,這里輸出一個(gè)字符串:
Code 1 ? static voidMain(string[] args){
Console.WriteLine("This is a simple string.");
}
現(xiàn)在考慮到該字符串將來可能發(fā)生變化,不知道該字符串將從何處取得,也就是說這里有可能是一個(gè)變化點(diǎn),也是一個(gè)擴(kuò)展點(diǎn),那我們現(xiàn)在使用MEF對(duì)其進(jìn)行重新設(shè)計(jì),我們將會(huì)把這個(gè)過程分成兩個(gè)部分,一部分用于提供字符串,而另一部分則用來使用字符串,定義一個(gè)字符串提供程序,大家注意到這里為OutputTitle屬性添加了一個(gè)Export特性,這標(biāo)識(shí)著此處為一個(gè)輸出,它使的MEF能夠?qū)ζ溥M(jìn)行識(shí)別,如下代碼所示:
Code 2 ? public class WeekStringProvider{
[Export("Caption")]
public String OutputTitle
{
get { return "星期六"; }
}
} ?
這里只是定義了一個(gè)簡單的屬性,其實(shí)在同一個(gè)類型可以定義多個(gè)輸出,Export同時(shí)指定了一個(gè)字符串的契約名稱,這意味著任何匹配契約名稱的程序都可以使用該擴(kuò)展。除此之外,我們還可以指定一個(gè)類型來代替字符串的契約名稱,后面會(huì)說到。我們?cè)俣x一個(gè)輸入,即用來消費(fèi)該字符串,同樣是一個(gè)簡單的屬性,不過這次添加的是Import特性:
Code 3 ? public class Client{
[Import("Caption")]
public String OutputTitle
{ get; set; }
}
?
現(xiàn)在有了輸出和輸入,就可以在主程序中進(jìn)行調(diào)用了,需要?jiǎng)?chuàng)建一個(gè)CompositionContainer容器,并添加所有的組件到該容器中,再調(diào)用它的Bind()方法,一旦調(diào)用該方法后,就可以使用所有的組件了,如下代碼所示:
Code 4 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);
}
?
輸出結(jié)果如下圖所示:
現(xiàn)在我們?cè)俣x另外一個(gè)擴(kuò)展程序,讓它返回一個(gè)日期字符串,如下代碼所示:
Code 5 ? public class DateStringProvider{
[Export("Caption")]
public String OutputTitle
{
get { return DateTime.Now.ToLongDateString(); }
}
}
?
修改一下組件注冊(cè)程序,如下代碼所示:
Code 6 ? 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);
}
?
輸出結(jié)果如下圖所示:?
上面的示例中我們是使用了命名契約,除此之外,還可以使用類型契約,如定義一個(gè)字符串提供者程序的接口:
Code 7 ?public interface IStringProvider? {?String?OutputTitle {?get;?set; } }現(xiàn)在輸出和輸入對(duì)應(yīng)的修改為如下代碼:
Code 8 public class DateStringProvider : IStringProvider{
[Export(typeof(IStringProvider))]
public String OutputTitle
{
get { return DateTime.Now.ToLongDateString(); }
}
} Code 9 ? public class Client
{
[Import(typeof(IStringProvider))]
public String OutputTitle
{ get; set; }
}
?
運(yùn)行后可以看到它與前面的示例效果是一樣的。
Duck Typing支持
了解DI的朋友可能都有這樣的疑問,其實(shí)上面的代碼就是一個(gè)依賴注入,微軟模式與實(shí)踐團(tuán)隊(duì)已經(jīng)開發(fā)出了Unity,為什么還需要一個(gè)MEF呢?其實(shí)MEF的定位并不是DI,在前面我已經(jīng)說過,它主要是用于應(yīng)用程序擴(kuò)展管理,下面我們?cè)倏匆粋€(gè)示例,它在這方面具有什么樣的優(yōu)勢(shì),看下面這段代碼:
Code 10 [ContractType("TerryLeeCalculatro")]public interface ICalculator
{
int Execute(int x,int y);
}
public class Client
{
[Import(typeof(ICalculator))]
public ICalculator Calculator { get; set; }
}
?
?
這里我們定義了一個(gè)輸入,它里面具有一個(gè)ICalculator的屬性,也就是說它需要的輸入是一個(gè)類型是ICalculator的實(shí)例。現(xiàn)在我們定義輸出,如下代碼所示:
Code 11 [Export(typeof(ICalculator))]public class SubCalculator : ICalculator
{
public int Execute(int x, int y)
{
return x - y;
}
}
?
在主函數(shù)中進(jìn)行調(diào)用:
Code 12 static void Main(string[] args){
Client client =new Client();
CompositionContainer container =new CompositionContainer();
container.AddComponent<Client>(client);
container.AddComponent<SubCalculator>(new SubCalculator());
container.Bind();
Console.WriteLine(client.Calculator.Execute(1,2));
}
?
輸出結(jié)果如下圖所示:
?
現(xiàn)在我們需要對(duì)該程序擴(kuò)展,讓其計(jì)算結(jié)果為兩個(gè)數(shù)相加,如果使用DI,我們可能會(huì)想到,再編寫一個(gè)支持加法計(jì)算的類,讓其實(shí)現(xiàn)ICalculator接口,然而這里我們重新定義了一個(gè)新的接口IMyCalculator:
Code 13?
[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)
{
return x + y;
}
}
這里重新定義了一個(gè)新接口IMyCalculator,我們?yōu)樗O(shè)置的契約類型和前面定義的接口ICalculator一致。而AddCalculator實(shí)現(xiàn)這個(gè)接口,同樣用Export標(biāo)識(shí)它為一個(gè)輸出。最后調(diào)用程序如下:
Code 14 ? static void Main(string[] args){
Client client =new Client();
CompositionContainer container =new CompositionContainer();
container.AddComponent<Client>(client);
container.AddComponent<AddCalculator>(new AddCalculator());
container.Bind();
Console.WriteLine(client.Calculator.Execute(1,2));
} ?
輸出結(jié)果如下圖所示:
?
大家可能已經(jīng)意識(shí)到了,上面示例中的輸入需要ICalculator類型,而我們擴(kuò)展的輸出卻是IMyCalculator類型,它僅僅是與ICalculator標(biāo)識(shí)為相同的契約類型,這種方式帶來了極大的靈活性,也就是說我們?cè)趯?duì)原有應(yīng)用程序進(jìn)行擴(kuò)展時(shí),并不需要與原有應(yīng)用程序產(chǎn)生任何依賴,可以獨(dú)立的進(jìn)行擴(kuò)展。
Plug-In支持
在前面的例子中,始終有一個(gè)問題沒有解決,就是當(dāng)每次編寫一個(gè)擴(kuò)展程序后,都需要修改代碼向CompositionContainer中注冊(cè)組件,這樣其實(shí)并沒有實(shí)現(xiàn)真正的擴(kuò)展,我們希望的擴(kuò)展是Plug-In機(jī)制。在MEF對(duì)于Plug-In提供了很好的支持,它提供了DirectoryWatchingComponentCatalog類來對(duì)指定的目錄進(jìn)行監(jiān)視,就是說我們定義好了輸入之后,只要把相關(guān)的輸出組件放在指定目錄中,MEF會(huì)通過反射來進(jìn)行自動(dòng)查找,如我們定義這樣的一個(gè)輸入:
Code 15 public class User{
[Import("Role")]
public String Role { get; set; }
}
?
現(xiàn)在定義輸出,我們把它放在一個(gè)單獨(dú)的類庫項(xiàng)目中:
Code 16 ? public classDatabaseProvider { [Export("Role")] public String AvailableRole { get { return"Developer"; } } }?
在主調(diào)用程序的目錄下,我們創(chuàng)建一個(gè)Extensions的目錄,然后把相關(guān)的擴(kuò)展組件都放在該目錄下,并在主調(diào)用程序中,為DirectoryWatchingComponentCatalog實(shí)例加入Extensions目錄,這樣就避免了與具體的擴(kuò)展應(yīng)用程序產(chǎn)生依賴,如下代碼所示:
Code 17 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();
}
?
?
運(yùn)行后輸出結(jié)果如下:
??
對(duì)于MEF來說,Duck Typing支持以及Plug-In支持才是它的優(yōu)勢(shì)所在,它不是一個(gè)簡單的DI容器,而是一個(gè)真正的管理擴(kuò)展框架。當(dāng)然了現(xiàn)在MEF還處于CTP階段,很多功能還不是很完善。在8月初,微軟還特意請(qǐng)到了Castle之父Hammett加入該項(xiàng)目組,擔(dān)任Program Manager,MEF的未來值得期待,更值得期待的是MEF將會(huì)為Silverlight應(yīng)用程序開發(fā)一個(gè)MEF子集,讓我們對(duì)于Silverlight程序也能夠方便的進(jìn)行擴(kuò)展。
Managed Extensibility Framework的官方主頁是:http://code.msdn.microsoft.com/mef。
總結(jié)
本文簡單介紹了Managed Extensibility Framework的一些使用,希望對(duì)大家有所幫助。
轉(zhuǎn)載于:https://www.cnblogs.com/tuyile006/archive/2011/06/02/2070092.html
總結(jié)
以上是生活随笔為你收集整理的使用MEF方便的扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: thinkphp导航高亮的方法
- 下一篇: Sencha Architect 2 的