MEF初体验之十:部件重组
一些应用程序被设计成在运行时可以动态改变。例如,一个新的扩展被下载,或者因为其它的多种多样的原因其它的扩展变得不可用。MEF处理这些多样的场景是依赖我们称作重组的功能来实现的,它可已在最初的组合后改变导入的值。
导入可以通知MEF它通过[Import]使用Allowrecomposition属性来支持重组。看下面的代码片段:
[Export] public class HttpServerHealthMonitor { [ImportMany(AllowRecomposition=true)] public IMessageSender[] Senders { get; set; } }
这告诉MEF,你的类准备来处理重组,并且,如果IMessageSender实现者可用性改变(一个新的实现者可用或不可用),这个集合将被改变以在catalog中反映此
变化。一旦部件选择了允许重组,无论什么时候在catalog中可用的实现者有改变,或实例被手动地从容器中添加/移除,这些
都将使可重组部件得到通知。
重组的附加说明
- 当重组发生时,我们将用一个新的实例来替换集合/数组的实例,我们将不会更新已存在的实例。在上面的例子中,如果一个新的IMessageSender实例出现了,Senders将被一个新的数组完全替换。这是为了促进现场安全。
- 重组几乎对于支持导入的所有类型都有效,像字段,属性和集合,但是它不支持构造器参数。
- 如果你的类型碰巧实现了IPartImportsSatisfiedNotification接口,无论重组何时发生,导入完成也将会被调用
最后举个例子:
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; using ClassLibrary2; using System.Timers; namespace RecompositionExample { class Program { [ImportMany(AllowRecomposition=true)] public IEnumerable<IMessageSender> Senders { get; set; } static void Main(string[] args) { Program p = new Program(); p.Compose(); p.Print(); Console.ReadKey(); } private AggregateCatalog catalog; private Timer t; void t_Elapsed(object sender, ElapsedEventArgs e) { catalog.Catalogs.Add(new DirectoryCatalog("Plugins", "*.dll")); t.Enabled = false; Console.WriteLine("-----------------"); Print(); } void Compose() { catalog = new AggregateCatalog(new AssemblyCatalog(Assembly.GetExecutingAssembly())); var container = new CompositionContainer(catalog); container.ComposeParts(this); t = new Timer(5000); t.Elapsed += t_Elapsed; t.Start(); } void Print() { foreach (var item in Senders) { item.Send("Hi,MEF"); } } } [Export(typeof(IMessageSender))] class EmailSender : IMessageSender { public void Send(string msg) { Console.WriteLine("Email sent:" + msg); } } class TcpSender : IMessageSender { public void Send(string msg) { throw new NotImplementedException(); } } }