MEF初体验之九:部件生命周期
理解MEF容器中部件的生命周期及其含義是非常重要的。鑒于MEF重點在開放端應(yīng)用程序,這將變得尤其重要的,一旦app ships和第三方擴(kuò)展開始運行,作為應(yīng)用程序的開發(fā)者將很好地控制這一系列的部件。生命周期可以被解釋為這樣一個部件期望的共享物,無論是一個新的部件被創(chuàng)建還是一個部件被關(guān)閉或釋放都由控制策略來翻譯。
Shared, Non Shared and ownership
通過使用PartCreationPolicyAttribute特性設(shè)置CreationPolicy(類級別)來定義一個部件的共享物。下面的值是受支持的:
Shared:部件作者告訴MEF,一個部件的實例可以存在在每一個容器中(指定將由容器創(chuàng)建關(guān)聯(lián)的該ComposablePart 的單個共享實例,并由所有請求者共享該實例)
NonShared:部件作者告訴MEF,一個部件每一次的導(dǎo)出請求都將由一個部件新的實例來提供服務(wù)。(指定將由容器為每個請求者創(chuàng)建一個關(guān)聯(lián)的該ComposablePart的新的非共享實例)
Any or not supplied value:部件作者允許部件既可以支持Shared,也可以支持NonShared.
可以使用[System.ComponentModel.Composition.PartCreationPolicyAttribute]特性在一個部件上定義創(chuàng)建策略:
這個容器將一直擁有它創(chuàng)建的部件的所有權(quán)。換句話說,該所有權(quán)從不會轉(zhuǎn)移到一個通過使用容器實例(直接地)或一個導(dǎo)入(間接地)來請求它的行動者上來。
導(dǎo)入也可以定義或者約束這種被用來提供導(dǎo)入值的部件策略創(chuàng)建。你需要做的一切是為RequiredCreationPolicy指定CreationPolicy枚舉值:
[Export] public class Importer {[Import(RequiredCreationPolicy=CreationPolicy.NonShared)]public Dependency Dep { get; set; } }對于與importer相關(guān)的部件需要使用共享的場景來說是很用的。默認(rèn)地,RequiredCreationPolicy被設(shè)置為Any,因此Shared或者NonShared部件都可以提供值。
| |||||||||||||||
?
?
?
?
?注意:當(dāng)兩邊都定義CreationPolicy為Any,結(jié)果它將是一個Shared部件。
來個例子:
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks;namespace PartLifetime {class Program{[ImportMany(RequiredCreationPolicy=CreationPolicy.Shared)]public IEnumerable<IMessageSender> Senders { get; set; }static void Main(string[] args){Program p = new Program();p.Compose();foreach (var item in p.Senders){item.Send("Hi,MEF");}Console.ReadKey();}void Compose(){AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());var container = new CompositionContainer(catalog);container.ComposeParts(this);}}interface IMessageSender{void Send(string msg);}[Export(typeof(IMessageSender))][PartCreationPolicy(CreationPolicy.Shared)]class EmailSender : IMessageSender{public void Send(string msg){Console.WriteLine("Email sent:" + msg);}}[Export(typeof(IMessageSender))][PartCreationPolicy(CreationPolicy.NonShared)]class SMSSender : IMessageSender{public void Send(string msg){Console.WriteLine("SMS sent:" + msg);}}}我們發(fā)現(xiàn),當(dāng)Import的請求創(chuàng)建策略為Shared,則自動匹配EmailSender組件;當(dāng)為NonShared時,自動匹配SMSSende組件;當(dāng)省略或者為Any時,自動匹配Shared和NonShared。
釋放容器
通常,一個容器實例是部件生命周期的持有者。由容器創(chuàng)建的部件實例擁有的生命周期取決于容器的生命周期。標(biāo)志容器生命周期結(jié)束的方式是釋放它。釋放一個容器的含義是:
- 實現(xiàn)IDisposable接口的部件將會調(diào)用Dispose方法
- 被容器占有的部件的引用將被清除
- Shared組件將被釋放和清除
- Lazy導(dǎo)出組件在容器被釋放后將不會工作
- 操作可能會拋出System.ObjectDisposedExecption
容器和部件引用
我們相信,.Net GC是適當(dāng)?shù)厍謇砜梢蕾嚨淖詈玫臇|西。然后,我們也需要提供一個有確定性行為的容器。因此,這個容器將不會擁有它創(chuàng)建的部件的引用,除非下面的條件之一成立:
- 這個部件被標(biāo)記為Shared
- 這個部件實現(xiàn)了IDisposable接口
- 一個或者多個部件被配置為允許重組
對于那些條件,部件引用將被容器擁有。結(jié)合這個事實,你可以有NonShared部件,并且一直從容器來請求它們,然后內(nèi)存需求將迅速成為一個問題。為了減輕這個問題,你應(yīng)該依靠在下面接下來的兩個話題的討論的策略。
作用域操作和資源提前回收
一些常見類型的應(yīng)用程序,像web apps和windows服務(wù),在每個桌面應(yīng)用上卻又很大不同。它們可能更加依賴批量簡短的操作。例如,一個windows服務(wù)可能會直接地監(jiān)視,一旦一批可預(yù)估的文件存在,就將開始一個批處理操作來轉(zhuǎn)換這些文件成另外一種格式。Web操作可能由每次請求操作所決定。
對于那些場景,你應(yīng)該使用子容器或者提前釋放對象。后者可以使容器釋放和清掉非共享的部件。
為了提前釋放對象,你需要調(diào)用由組合容器暴露的ReleaseExport方法。
var batchProcessorExport = container.GetExport<IBatchProcessor>();var batchProcessor = batchProcessorExport.Value; batchProcessor.Process();container.ReleaseExport(batchProcessorExport);容器分層
另一種解決相同問題的方式是使用容器分層。你可以創(chuàng)建容器并將它連接到一個父容器并作為其子容器。注意除非你提供了一個不同的catalog到子容器中,否則將不會有很大幫助,因為仍然會在父容器中實例化。
因此,你應(yīng)該做的是,基于一種標(biāo)準(zhǔn)過濾父容器,這種標(biāo)準(zhǔn)是應(yīng)該被創(chuàng)建在父容器中的一系列部件和那些應(yīng)該被創(chuàng)建在子容器中的部件區(qū)分開來,或者是,你應(yīng)該完全指定一個新的catalog來暴露一系列應(yīng)該被創(chuàng)建在子容器中的部件。子容器正如所期望的那樣是短期存在的,創(chuàng)建在它里面的部件將會更早地被釋放掉。一個通用的解決辦法是將共享的部件創(chuàng)建在父容器中,而將非共享的部件創(chuàng)建在子容器中。由于共享部件可能會依賴由非共享部件提供的導(dǎo)出,這時主catalog必須包含整個一系列的部件而子容器應(yīng)該有一個僅包含非共享部件的過濾主容器的視圖。
可處理命令
可處理命令并不能以任何方式確保。那意味著你不應(yīng)該在你的dispose方法上試圖使用導(dǎo)入。例如:
[Export] public class SomeService : IDisposable {[Import]public ILogger Logger { get; set; }public void Dispose(){Logger.Info("Disposing"); // might throw exception! } }在你的dispose方法實現(xiàn)上使用導(dǎo)入的logger實例可能會有問題,因為這個ILogger契約的實現(xiàn)也可能是可處理的,而此時可能它已經(jīng)被處理掉了。
添加部件/移除部件
并不是每一個部件都是由容器創(chuàng)建的。你也可以從容器中添加和移除部件。這個過程觸發(fā)了容器,
使其開始創(chuàng)建部件來滿足遞歸添加的部件的依賴。當(dāng)部件被移除時,MEF足夠聰明,它將會回收資源并且處理掉被部件添加的非共享部件。
注意:MEF將從不會占有你提供的實例的所有權(quán),但是,它有由它自己創(chuàng)建的滿足你實例導(dǎo)入的部件的所有權(quán)。
?
轉(zhuǎn)載于:https://www.cnblogs.com/jellochen/p/3667704.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的MEF初体验之九:部件生命周期的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实现技术3次作业 谢筱 11012207
- 下一篇: oracle pl/sql 基础