MEF核心筆記(4)細說MEF中的Attribute [下]今天,我們繼續(xù)MEF的學(xué)習(xí)記錄,這次內(nèi)容感覺比較重要,所以,特別放到單獨一篇來說,這也是MEF很有特色的地方,相信這其中的亮點,會讓你感觸良多的。 本篇主要有以下幾節(jié)內(nèi)容:
一、部件的創(chuàng)建規(guī)則我們知道,在目前主流的IoC框架里,注入對象的創(chuàng)建都可以進行個性化配置,例如是否以單例方式創(chuàng)建(也就是共享一個對象,給所有需要注入的地方調(diào)用),不僅如此,如果屬性【Remoting】技術(shù)的朋友應(yīng)該也會接觸到服務(wù)對象的實例創(chuàng)建,另外WCF服務(wù)對象也亦是如此,他們都有各自的創(chuàng)建規(guī)則。同樣,MEF的部件也有它的創(chuàng)建規(guī)則。 涉及到MEF部件的創(chuàng)建規(guī)則,首先我們要看下【PartCreationPolicyAttribute】這個特性,因為部件創(chuàng)建的規(guī)則,主要是靠該特性來控制的。該特性只有一個屬性【CreationPolicy】,類型為【System.ComponentModel.Composition.CreationPolicy】的枚舉: 對應(yīng)的【ImportAttribute】、【ImportManyAttribute】,都有一個【RequiredCreationPolicy】的屬性,類型也是此枚舉。從這里我們就不難看出,使用【PartCreationPolicyAttribute】我們可以指定導(dǎo)出部件的創(chuàng)建規(guī)則,通過導(dǎo)入的【RequiredCreationPolicy】的屬性我們可以設(shè)定導(dǎo)入類型的創(chuàng)建規(guī)則。 根據(jù)【CreationPolicy】枚舉的值,我們很容易就能看出其代表的意義,【Shared】代表共享部件,即單例,所有的導(dǎo)入都使用一個實例,如果組合引擎中沒有該實例,則會創(chuàng)建,一旦有了,就不會再創(chuàng)建;【NonShared】和【Shared】相對應(yīng),即每次導(dǎo)入都創(chuàng)建一個新的實例,所有導(dǎo)入的實例都擁有自己唯一的狀態(tài),數(shù)據(jù)不共享;【Any】只是為了匹配導(dǎo)入導(dǎo)出,有下面一張匹配表:
只有滿足上面這張表,導(dǎo)入導(dǎo)出才會匹配,下面我們做一個很簡單的示例: namespace MEFTest { class Program { private static CompositionContainer _container; static void Main(string[] args) { var catalog = new AssemblyCatalog(typeof(Program).Assembly); _container = new CompositionContainer(catalog); var studentManager1 = _container.GetExportedValue<StudentManager>(); var studentManager2 = _container.GetExportedValue<StudentManager>(); Console.WriteLine(object.ReferenceEquals(studentManager1, studentManager2)); Console.WriteLine(object.ReferenceEquals(studentManager1.Student, studentManager2.Student)); while (true) { Console.ReadLine(); } } } //單例導(dǎo)出 [Export, PartCreationPolicy(CreationPolicy.Shared)] public class Student { public string Name { get; set; } public int Age { get; set; } } //非單例導(dǎo)出 [Export, PartCreationPolicy(CreationPolicy.NonShared)] public class StudentManager { //默認的是 Any [Import] public Student Student { get; set; } } } 最后輸出的是一個false和true,看懂了這個示例,你就看懂整個創(chuàng)建規(guī)則了,如果沒有看懂,抱歉,只能說明,我的示例寫得太爛了。 此外,我們可以預(yù)先在容器中定義導(dǎo)出,這樣的定義不需要【Export】特性描述類型,并且這樣輸出的永遠是單例: _container.ComposeExportedValue<DateTime>(DateTime.Now); Console.WriteLine(_container.GetExportedValue<DateTime>()); 二、元數(shù)據(jù)和元數(shù)據(jù)視圖在MEF中,我們可以在導(dǎo)出部件時附加一些數(shù)據(jù),而這些附加導(dǎo)出的數(shù)據(jù)就是元數(shù)據(jù),附加導(dǎo)出數(shù)據(jù)的結(jié)構(gòu)就是元數(shù)據(jù)視圖,這是我覺得MEF中,最令人激動的功能。 導(dǎo)出元數(shù)據(jù),我們使用【ExportMetadata】特性,設(shè)置該特性的【Name】和【Value】,即可導(dǎo)出對應(yīng)的元數(shù)據(jù),我們以示例來說: class Program { private static CompositionContainer _container; static void Main(string[] args) { var catalog = new AssemblyCatalog(typeof(Program).Assembly); _container = new CompositionContainer(catalog); var studentManager = _container.GetExportedValue<StudentManager>(); Console.WriteLine(studentManager.Student.Metadata.ClassName); while (true) { Console.ReadLine(); } } } public interface IClassMetadata { string ClassName { get; } [DefaultValue("")] string OtherInfo { get; } } [Export] [ExportMetadata("ClassName", "一年級三班")] public class Student { public string Name { get; set; } public int Age { get; set; } } [Export] public class StudentManager { [Import] public Lazy<Student, IClassMetadata> Student { get; set; } } 在該示例中,【IClassMetadata】即是元數(shù)據(jù)視圖,我們導(dǎo)出的元數(shù)據(jù)必須滿足該接口格式,否則【StudentManager】的【Improt】就會失敗。我們在【Student】類上只導(dǎo)出了【ClassName】,而我們的元數(shù)據(jù)視圖中還有一個【OtherInfo】的屬性,這里需要注意一下,如果要提供默認值,必須標(biāo)記上【DefaultValue】,否則如果不賦值(導(dǎo)出)的話,就匹配不了該元數(shù)據(jù)視圖,也就是說,如果我們將【DefaultValue】去掉,該程序就不會正確執(zhí)行了(【StudentManager】的【Improt】會失?。?。 除了使用【ExportMetadata】特性導(dǎo)出元數(shù)據(jù)外,我們還可定義自己的導(dǎo)出特性來導(dǎo)出元數(shù)據(jù),我們可以繼承【ExportAttribute】,并且一定要有【MetadataAttribute】特性,以上的示例,我們可以改成這樣: public interface IClassMetadata { string ClassName { get; } string OtherInfo { get; } } [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] public class ExportStudent : ExportAttribute, IClassMetadata { public ExportStudent() : base() { } public ExportStudent(string contractName) : base(contractName) { } public ExportStudent(Type contractType) : base(contractType) { } public ExportStudent(string contractName, Type contractType) : base(contractName, contractType) { } public string ClassName { get; set; } //如果可選,必須要加上 [DefaultValue("")] public string OtherInfo { get; set; } } [ExportStudent(ClassName = "一年級三班")] public class Student { public string Name { get; set; } public int Age { get; set; } } 通過繼承【ExportAttribute】,我們可以實現(xiàn)比較強類型的編程,再也不怕字符串拼錯,不過相比與【ExportMetadata】似乎是麻煩了一點點。 三、部件組裝通知這是個比較簡單,但又很有用的功能,特別是在我們需要完成一些自動化的操作時(例如日志)。部件組裝通知,就是當(dāng)某個組件引用的部件都能滿足導(dǎo)入,在返回已經(jīng)組裝完成的組件之前,先通知該組件。 若要得到通知,我們只要實現(xiàn)【IPartImportsSatisfiedNotification】接口即可,該接口有一個【OnImportsSatisfied】的方法,即通知組件部件組裝的地方。請看簡單的示例: class Program { private static CompositionContainer _container; static void Main(string[] args) { var catalog = new AssemblyCatalog(typeof(Program).Assembly); _container = new CompositionContainer(catalog); var studentManager = _container.GetExportedValue<MyComponent>(); while (true) { Console.ReadLine(); } } } [Export] class MyComponent : IPartImportsSatisfiedNotification { public void OnImportsSatisfied() { Console.WriteLine("OK!~"); } } 該示例很簡單,但也將【IPartImportsSatisfiedNotification】淋漓盡致的體現(xiàn)了,由于【MyComponent】滿足了組裝條件,所以該通知一定能得到執(zhí)行。 四、總結(jié)這一篇和前一篇是MEF非常核心的內(nèi)容,了解到這里,我們基本上已經(jīng)完全可以勝任MEF的開發(fā)使用了。后續(xù)打算開發(fā)一個程序,來深入體會MEF具體使用,以及設(shè)計層面上的思想,大家一起期待吧。 作者:MKiller
出處:http://www.cnblogs.com/prinsun/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利.
|
|
來自: 昵稱10504424 > 《C#》