MEF框架学习之旅(十)重组
重新组合是 MEF 的一项功能,此功能允许部件在系统中出现新的匹配导出时自动更新其导入。重新组合在某些方案中十分有用,AllowRecomposition=true参数就表示运行在有新的部件被装配成功后进行部件集的重组。
例如从远程服务器下载部件时。SalesOrderManager 可以进行更改,以便在其启动时,可启动多个可选视图的下载。这些视图显示时,会出现在视图工厂中。为了使 ViewFactory 可重新组合,我们在 Views 属性的 ImportMany 特性上将 AllowRecomposition 属性设置为 true,如下所示:
代码段
[Export] public class ViewFactory { [ImportMany(AllowRecomposition=true)] IEnumerable<Lazy<IView, IViewMetadata>> Views { get; set; } public IEnumerable<View>GetViews(ViewTypesviewType)
{ return Views.Where(v=>v.Metadata.ViewType.Equals(viewType)).Select(v=>v.Value); } }
进行重新组合时,Views 集合将立刻替换为包含一组更新过的视图的新集合。
启用重新组合后,应用程序可从服务器下载其他程序集并将这些程序集添加到容器。可通过 MEF 的目录执行此操作。MEF 提供了多个目录,其中有两个目录可重新组合。DirectoryCatalog(您已看到过)是可通过调用其 Refresh 方法来重新组合的目录。另一个可重新组合的目录是 AggregateCatalog,这是目录的目录。您可使用 Catalogs 集合属性向该目录添加目录,这会启动重新组合。我将使用的最后一个目录是 AssemblyCatalog,该目录接受一个它随后将在其之上构建目录的程序集。图 2 演示一个示例,说明如何结合使用这些目录进行动态下载。
图 2 使用 MEF 目录进行动态下载
代码段
void App_Startup(object sender, StartupEventArgs e) { var catalog = new AggregateCatalog(); catalog.Catalogs.Add(newDirectoryCatalog((@"\."))); var container = new CompositionContainer(catalog); container.Composeparts(this); base.MainWindow = MainWindow; this.DownloadAssemblies(catalog); } private void DownloadAssemblies(AggregateCatalog catalog) { //asynchronously downloads assemblies and calls AddAssemblies } private void AddAssemblies(Assembly[] assemblies, AggregateCatalog catalog) { var assemblyCatalogs = new AggregateCatalog(); foreach(Assembly assembly in assemblies) assemblyCatalogs.Catalogs.Add(new AssemblyCatalog(assembly)); catalog.Catalogs.Add(assemblyCatalogs); }
图 2 中的容器是使用 AggregateCatalog 创建的。该容器随后将 DirectoryCatalog 添加到其中,以在 bin 文件夹中获取本地部件。聚合目录会传递到 DownloadAssemblies 方法,该方法异步下载程序集,然后调用 AddAssemblies。该方法会创建新的 AggregateCatalog,向该目录为每个下载程序集添加 AssemblyCatalogs。然后,AddAssemblies 添加包含主要聚合的程序集的 AggregateCatalog。它之所以采用这种方式进行添加,是为了一次性完成重新组合,而不是反复进行(在直接添加程序集目录时会出现这种情况)。
进行重新组合时,集合会立即更新。结果因集合属性类型而异。如果属性类型是 IEnumerable<T>,则它将替换为新实例。如果它是继承自 List<T> 或 ICollection 的具体集合,则 MEF 将对每一项依次调用 Clear 和 Add。无论是哪一种情况,都意味着在使用重新组合时必须考虑线程安全。重新组合不仅与添加有关,也与删除有关。如果从容器中移除目录,则也会移除这些部件。
相关阅读: