MEF初体验之七:Using Catalogs
MEF特性化编程模型的价值主张之一是通过catalogs动态发现部件的能力。Catalogs允许应用程序很容易地消费那些通过[Export]已经自我注册的exports。
Assembly Catalog
为了在一个特定的程序集中发现所有的exports,可以使用System.ComponentModel.Composition.Hosting.AssemblyCatalog类。
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
Directory Catalog
为了在一个目录中所有程序集中发现所有的exports,可以使用System.ComponentModel.Composition.Hosting.DirectoryCatalog类。
var catalog = new DirectoryCatalog("Extensions");
如果使用的是一个相对的目录,它将相对于当前AppDomain的基本目录。
DirectoryCatalog将扫描这个目录一次,当这个目录发生变化时,它将并不会自动刷新。然而,你可以实现你自己的扫描机制,在catalog上调用Refresh()方法使它重新扫描。一旦它重新扫描,将发生重组。
var catalog = new DirectoryCatalog("Extensions"); //some scanning logic catalog.Refresh();
注意:在sliverlight中不支持DirectoryCatalog。
Aggregate Catalog
当AssemblyCatalog and DirectoryCatalog单独不充足,需要结合的catalogs时,应用程序可以使用System.ComponentModel.Composition.Hosting.AggregateCatalog类。一个AggregateCatalog将多个catalogs组合到一个单一的catalog中。通用的模式是添加当前执行的程序集和第三方扩展的一个directory catalog。你可以将要组合的catalog作为AggregateCatalog构造器参数或者使用AggregateCatalog的Catalogs属性来直接添加。
var catalog = new AggregateCatalog( new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()), new DirectoryCatalog("Extensions"));
Type Catalog
为了在一系列指定的类型中发现所有的导出,将可以使用System.ComponentModel.Composition.Hosting.TypeCatalog类。
var catalog = new TypeCatalog(typeof(type1), typeof(type2), ...);
DeploymentCatalog - Sliverlight only
在Sliverlight中,MEF包含DeploymentCatalog,用来动态下载远程XAPs。有关更多DeploymentCatalog内容请查看DeploymentCatalog
Using catalog with a Container
为了使用catalog和container,只需简单地将catalog传到container的构造器即可。
var container = new CompositionContainer(catalog);
最后举个例子:
首先,在CommonLib类库中定义了一个接口:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CommonLib { public interface ILogger { void Log(string msg); } }
然后,创建CatalogLib类库,引用CommonLib类库,并在里面定义一个ILogger类型契约的exports:
using CommonLib; using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CatalogLib { [Export(typeof(ILogger))] public class FileLogger:ILogger { public void Log(string msg) { Console.WriteLine("File Logger:"+msg); } } }
最后,创建CatalogsSample控制台程序,将CatalogLib的生成路径也改为该生成路径,并引用CommonLib,也创建一个ILogger类型契约的exports,在入口处组合,代码如下:
using CommonLib; 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 CatalogsSample { class Program { [ImportMany] public IEnumerable<ILogger> Loggers { get; set; } static void Main(string[] args) { Program p = new Program(); p.Compose(); foreach (var item in p.Loggers) { item.Log("Hi,MEF"); } Console.ReadKey(); } void Compose() { var catalog = new AggregateCatalog(new AssemblyCatalog(Assembly.GetExecutingAssembly()), new DirectoryCatalog(".")); var container = new CompositionContainer(catalog); container.ComposeParts(this); } } [Export(typeof(ILogger))] class DBLogger : ILogger { public void Log(string msg) { Console.WriteLine("DB Logger:" + msg); } } }
输出如图: