导航网站模板免费,仅有网站做app,网站建设硬件和软件技术环境配置,福建网站建设优化理解MEF容器中部件的生命周期及其含义是非常重要的。鉴于MEF重点在开放端应用程序#xff0c;这将变得尤其重要的#xff0c;一旦app ships和第三方扩展开始运行#xff0c;作为应用程序的开发者将很好地控制这一系列的部件。生命周期可以被解释为这样一个部件期望的共享物这将变得尤其重要的一旦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(RequiredCreationPolicyCreationPolicy.NonShared)]public Dependency Dep { get; set; }
} 对于与importer相关的部件需要使用共享的场景来说是很用的。默认地RequiredCreationPolicy被设置为Any因此Shared或者NonShared部件都可以提供值。 -Part.AnyPart.SharedPart.NonSharedImport.AnySharedSharedNon SharedImport.SharedSharedSharedNo MatchImport.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(RequiredCreationPolicyCreationPolicy.Shared)]public IEnumerableIMessageSender 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.GetExportIBatchProcessor();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 partcontainer.ComposeParts(root);//...use the composed root instance//remove external part//var batch new CompositionBatch();//var rootPart batch.AddExportedValueRoot(new Root());//container.Compose(batch);//batch new CompositionBatch();//batch.RemovePart(rootPart);//container.Compose(batch);container.ReleaseExportNonSharedDependency(new LazyNonSharedDependency());Console.ReadKey();}}class Root{[Import(RequiredCreationPolicyCreationPolicy.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