MEF初體驗之九:部件生命周期

理解MEF容器中部件的生命周期及其含義是非常重要的。鑒于MEF重點在開放端應用程序,這將變得尤其重要的,一旦app ships和第三方擴展開始運行,作為應用程序的開發者將很好地控制這一系列的部件。生命周期可以被解釋為這樣一個部件期望的共享物,無論是一個新的部件被創建還是一個部件被關閉或釋放都由控制策略來翻譯。

Shared, Non Shared and ownership

通過使用PartCreationPolicyAttribute特性設置CreationPolicy(類級別)來定義一個部件的共享物。下面的值是受支持的:
Shared:部件作者告訴MEF,一個部件的實例可以存在在每一個容器中(指定將由容器創建關聯的該ComposablePart 的單個共享實例,并由所有請求者共享該實例)
NonShared:部件作者告訴MEF,一個部件每一次的導出請求都將由一個部件新的實例來提供服務。(指定將由容器為每個請求者創建一個關聯的該ComposablePart的新的非共享實例)
Any or not supplied value:部件作者允許部件既可以支持Shared,也可以支持NonShared.

可以使用[System.ComponentModel.Composition.PartCreationPolicyAttribute]特性在一個部件上定義創建策略:

[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(typeof(IMessageSender))]
public class SmtpSender : IMessageSender
{
}

這個容器將一直擁有它創建的部件的所有權。換句話說,該所有權從不會轉移到一個通過使用容器實例(直接地)或一個導入(間接地)來請求它的行動者上來。

導入也可以定義或者約束這種被用來提供導入值的部件策略創建。你需要做的一切是為RequiredCreationPolicy指定CreationPolicy枚舉值:

[Export]
public class Importer
{[Import(RequiredCreationPolicy=CreationPolicy.NonShared)]public Dependency Dep { get; set; }
}

對于與importer相關的部件需要使用共享的場景來說是很用的。默認地,RequiredCreationPolicy被設置為Any,因此Shared或者NonShared部件都可以提供值。

-Part.AnyPart.SharedPart.NonShared
Import.AnySharedSharedNon Shared
Import.SharedSharedSharedNo Match
Import.NonSharedNon SharedNo MatchNon Shared

?

?

?

?

?注意:當兩邊都定義CreationPolicy為Any,結果它將是一個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);}}}

我們發現,當Import的請求創建策略為Shared,則自動匹配EmailSender組件;當為NonShared時,自動匹配SMSSende組件;當省略或者為Any時,自動匹配Shared和NonShared。

釋放容器

通常,一個容器實例是部件生命周期的持有者。由容器創建的部件實例擁有的生命周期取決于容器的生命周期。標志容器生命周期結束的方式是釋放它。釋放一個容器的含義是:

  • 實現IDisposable接口的部件將會調用Dispose方法
  • 被容器占有的部件的引用將被清除
  • Shared組件將被釋放和清除
  • Lazy導出組件在容器被釋放后將不會工作
  • 操作可能會拋出System.ObjectDisposedExecption

容器和部件引用

我們相信,.Net GC是適當地清理可依賴的最好的東西。然后,我們也需要提供一個有確定性行為的容器。因此,這個容器將不會擁有它創建的部件的引用,除非下面的條件之一成立:

  • 這個部件被標記為Shared
  • 這個部件實現了IDisposable接口
  • 一個或者多個部件被配置為允許重組

對于那些條件,部件引用將被容器擁有。結合這個事實,你可以有NonShared部件,并且一直從容器來請求它們,然后內存需求將迅速成為一個問題。為了減輕這個問題,你應該依靠在下面接下來的兩個話題的討論的策略。

作用域操作和資源提前回收

一些常見類型的應用程序,像web apps和windows服務,在每個桌面應用上卻又很大不同。它們可能更加依賴批量簡短的操作。例如,一個windows服務可能會直接地監視,一旦一批可預估的文件存在,就將開始一個批處理操作來轉換這些文件成另外一種格式。Web操作可能由每次請求操作所決定。

對于那些場景,你應該使用子容器或者提前釋放對象。后者可以使容器釋放和清掉非共享的部件。

為了提前釋放對象,你需要調用由組合容器暴露的ReleaseExport方法。

var batchProcessorExport = container.GetExport<IBatchProcessor>();var batchProcessor = batchProcessorExport.Value;
batchProcessor.Process();container.ReleaseExport(batchProcessorExport);

容器分層

另一種解決相同問題的方式是使用容器分層。你可以創建容器并將它連接到一個父容器并作為其子容器。注意除非你提供了一個不同的catalog到子容器中,否則將不會有很大幫助,因為仍然會在父容器中實例化。

因此,你應該做的是,基于一種標準過濾父容器,這種標準是應該被創建在父容器中的一系列部件和那些應該被創建在子容器中的部件區分開來,或者是,你應該完全指定一個新的catalog來暴露一系列應該被創建在子容器中的部件。子容器正如所期望的那樣是短期存在的,創建在它里面的部件將會更早地被釋放掉。一個通用的解決辦法是將共享的部件創建在父容器中,而將非共享的部件創建在子容器中。由于共享部件可能會依賴由非共享部件提供的導出,這時主catalog必須包含整個一系列的部件而子容器應該有一個僅包含非共享部件的過濾主容器的視圖。

可處理命令

可處理命令并不能以任何方式確保。那意味著你不應該在你的dispose方法上試圖使用導入。例如:

[Export]
public class SomeService : IDisposable
{[Import]public ILogger Logger { get; set; }public void Dispose(){Logger.Info("Disposing"); // might throw exception!
    }
}

在你的dispose方法實現上使用導入的logger實例可能會有問題,因為這個ILogger契約的實現也可能是可處理的,而此時可能它已經被處理掉了。

添加部件/移除部件

并不是每一個部件都是由容器創建的。你也可以從容器中添加和移除部件。這個過程觸發了容器,
使其開始創建部件來滿足遞歸添加的部件的依賴。當部件被移除時,MEF足夠聰明,它將會回收資源并且處理掉被部件添加的非共享部件。

注意:MEF將從不會占有你提供的實例的所有權,但是,它有由它自己創建的滿足你實例導入的部件的所有權。

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace PartLifetime
{class Example{static void Main(){var catalog = new AssemblyCatalog(typeof(Program).Assembly);var container = new CompositionContainer(catalog);var root = new Root();//add external part
            container.ComposeParts(root);//...use the composed root instance//remove external part//var batch = new CompositionBatch();//var rootPart = batch.AddExportedValue<Root>(new Root());//container.Compose(batch);//batch = new CompositionBatch();//batch.RemovePart(rootPart);//container.Compose(batch);container.ReleaseExport<NonSharedDependency>(new Lazy<NonSharedDependency>());Console.ReadKey();}}class Root{[Import(RequiredCreationPolicy=CreationPolicy.NonShared)]public NonSharedDependency Dep { get; set; }}[Export,PartCreationPolicy(CreationPolicy.NonShared)]class NonSharedDependency : IDisposable{public void Dispose(){Console.WriteLine("Disposed");}}}

?

轉載于:https://www.cnblogs.com/jellochen/p/3667704.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386318.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386318.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386318.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ASP.NET MVC中在Action獲取提交的表單數據方法總結 (4種方法,轉載備忘)

有Index視圖如下&#xff1a; 視圖代碼如下&#xff1a; [html] view plaincopyprint?<% Page Language"C#" MasterPageFile"~/Views/Shared/Site.Master" Inherits"System.Web.Mvc.ViewPage" %> <asp:Content ID"Content1&qu…

解析底層原理!Android開發者面試如何系統復習?幫你突破瓶頸

現狀 后端轉 Android 我該從何處下手&#xff0c;現在學習 android 晚嗎&#xff1f; 我的回答是晚還不至于&#xff0c;因為目前是市場趨于穩定正常&#xff0c;這個是市場發展的比如趨勢&#xff0c;現在火爆大家都看好的人工智能&#xff0c;大數據&#xff0c;猶如2010年…

SpringMVC與Struts2區別與比較總結

SpringMVC與Struts2區別與比較總結 1、Struts2是類級別的攔截&#xff0c; 一個類對應一個request上下文&#xff0c;SpringMVC是方法級別的攔截&#xff0c;一個方法對應一個request上下文&#xff0c;而方法同時又跟一個url對應&#xff0c;所以說從架構本身上SpringMVC就容易…

解析底層原理!月薪20k+的Android面試都問些什么?深夜思考

正文 Android行業主要問題是初級Android太多了&#xff0c;會寫xml和Activity的程序員太多了&#xff0c;初中級程序員面臨很大的競爭&#xff0c;現狀也就偏于高級開發者。越來越多的初中級Android程序員找不到滿意的工作&#xff0c;甚至根本找不到工作&#xff01;所以很多…

windows2000 ,windowsXP和windows2003共享頁面文件

為了緩解大型應用程序對系統內存的壓力,windows系統采用了頁面文件(windows2000以后被叫做pagefile.sys,放在系統分區的根目錄下),來存儲內存中暫時不用的數據或程序.從而提高系統的性能.一般應該將頁面文件的最小值設置為物理內存的2倍,最大值也設為最小值的2倍.拿現在主流的5…

解鎖Android性能優化的五大誤區!滿滿干貨指導

籠統來說&#xff0c;中年程序員容易被淘汰的原因其實不外乎三點。 1、輸出能力已到頂點。這個人奮斗十來年了&#xff0c;依舊碌碌無為&#xff0c;很明顯這人的天花板就這樣了&#xff0c;說白了&#xff0c;天賦就這樣。 2、適應能力越來越差。年紀大&#xff0c;有家庭&…

python查看文件的編碼格式

pip install chardet 執行 import chardet f open(a.doc,r) data f.read() print chardet.detect(data) 結果 {confidence: 0.64465744, encoding: utf-8} 前面是相似度 后面是編碼格式 或者 return chardet.detect(data).get("encoding") 直接獲取文件編碼格式 轉…

意外收獲字節跳動內部資料,一篇文章幫你解答

前言 俗話說“生于憂患&#xff0c;死于安樂”&#xff0c;其實大部分中年危機&#xff0c;就是在安樂中產生的。 有的人或許會反駁&#xff0c;“照你這么說&#xff0c;我還必須奮斗了&#xff0c;不奮斗就要死&#xff0c;難道選擇安逸的生活就不對嗎&#xff1f;我就沒有…

成功跳槽百度工資從15K漲到28K,已整理成文檔

開頭 在一般的互聯網公司的技術人員的面試中&#xff0c;大概會經歷3到4輪的面試&#xff0c;差不多2-3輪的技術面&#xff0c;還有1輪的HR面試&#xff0c;有人面試題是有關“目標”&#xff0c;有的關于“方法”&#xff0c;有的關于“算法”&#xff0c;有的關于“基礎”。…

oracle pl/sql 基礎

PL/SQL筆記PL/SQL塊中只能直接嵌入SELECT,DML(INSERT,UPDATE,DELETE)以及事務控制語句(COMMIT,ROLLBACK,SAVEPOINT),而不能直接嵌入DDL語句(CREATE,ALTER,DROP)和DCL語句(GRANT,REVOKE) 1.檢索單行數據 1.1使用標量變量接受數據 v_ename emp.ename%type; v_sal emp.sal%…

我三年開發經驗,從字節跳動抖音離職后,吐血整理

前言 前不久寫過一篇博客&#xff0c;里面介紹了一位朋友由二本渣渣畢業在外包公司工作兩年多后&#xff0c;跳槽逆襲成功&#xff0c;現在進入了OPPO公司的故事。 后面很多朋友私信我&#xff0c;表示想要這位朋友的面經。 其實我覺得&#xff0c;大家對面經完全沒必要這么…

熊逸《唐詩50講》田園篇 - 學習筆記與感想

此篇已加入熊逸《唐詩50講》學習筆記索引目錄。 一、田園篇具體內容 田園牧歌對于在現代社會里打拼的人們來說&#xff0c;距離一萬光年&#xff0c;但是身心俱疲的時候&#xff0c;讀兩首田園詩卻是最好的治愈&#xff0c;因為詩里歲月柔軟、風物沛然。這一篇里&#xff0c;熊…

我三年開發經驗,從字節跳動抖音離職后,滿滿干貨指導

前言 程序員這個行業&#xff0c;日新月異&#xff0c;技術體系更新速度快&#xff0c;新技術新框架層出不窮&#xff0c;所有的技術都像是一個無底洞&#xff0c;當你學得越多就會發現不懂的越多&#xff0c;不懂的越多&#xff0c;需要學習的就更多。 因此&#xff0c;一旦…

jquery $(this)和this

jQuery中this與$(this)的區別 $("#textbox").hover( function() { this.title "Test"; }, fucntion() { this.title "OK”; } ); 這里的this其實是一個Html 元素(textbox)&#xff0c;…

我了解到的面試的一些小內幕!順利通過阿里Android崗面試

前言 從畢業到現在面試也就那么幾家公司&#xff0c;單前幾次都比較順利&#xff0c;在面到第三家時都給到了我offer&#xff01;前面兩次找工作&#xff0c;沒考慮到以后需要什么&#xff0c;自己的對未來的規劃是什么&#xff0c;只要有份工作&#xff0c;工資符合自己的要求…

React-redux框架之connect()與Provider組件 用法講解

react-redux 在react-redux 框架中&#xff0c;給我提供了兩個常用的API來配合Redux框架的使用&#xff0c;其實在我們的實際項目開發中&#xff0c;我們完全可以不用react-redux框架&#xff0c;但是如果使用此框架&#xff0c;就如虎添翼了。 我們來簡單聊聊這兩個常用的API …

我們究竟還要學習哪些Android知識?吐血整理

前言 閑來無事在家偶然翻到了之前整理的文檔和面試要做到準備路線&#xff0c;雖然內容有點多&#xff0c;但是技多不壓身&#xff0c;多多益善 本部分內容是關于Android進階的一些知識總結&#xff0c;涉及到的知識點比較雜&#xff0c;不過都 是面試中幾乎常問的知識點&…

海明距離

處理 非遞減或者非遞增 排列 的時候 &#xff0c;可以使用計數排序&#xff0c;將時間 復雜度變為 O&#xff08;N&#xff09;&#xff0c;空間復雜度變為O&#xff08;1&#xff09;。 1 int heightChecker(vector<int>& heights) {2 vector<int> res(10…

我們究竟還要學習哪些Android知識?滿滿干貨指導

咸魚翻身不斷上演 2018年5月份&#xff0c;北京&#xff0c;在所謂的互聯網寒冬里&#xff0c;一個普通二本的學生&#xff0c;在小公司工作一年后&#xff0c;跳槽拿到了百度的offer&#xff0c;月薪從9k變為17k&#xff0c;漲薪幅度接近100%。 2018年底&#xff0c;上海&am…

ElasticSearch6.3腳本更新

使用上篇文章創建的索引進行學習&#xff1a;https://www.cnblogs.com/wangymd/p/11200996.html 官方文檔&#xff1a;https://www.elastic.co/guide/en/elasticsearch/painless/6.3/painless-examples.html 1、腳本更新指定字段 方式1&#xff1a; POST test_index/test_type…