一些应用程序被设计成在运行时可以动态改变。例如,一个新的扩展被下载,或者因为其它的多种多样的原因其它的扩展变得不可用。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();
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();
}
} }