起因:工作需要针对不同类型的文件做不同的处理。打个比方,txt文件,直接打印,doc文件,直接发email,jpg文件,上传xxx相册站点。
其实这个问题在学习最基本的工厂模式的时候早已经解决了,稍有点面向对象基础的,都可以写出这样一个文件管理器。再有新类型文件处理的时候,只需要在加一个实现类,再在工厂里面加一个if判断,返回一个具体的处理实例即可,上层不必改动。
要干掉工厂里面的if,则必须要请出ioc容器了。MEF就是微软自家的托管可扩展框架,在这里被我用成了ioc容器,其他的功能,不求甚解。
我们先拿MEF练练手,再应用到具体的项目中。概念什么的先扔到一边。
新建一个控制台应用程序项目和一个类库项目,两个项目均引用MEF库。类库项目中新建三个类文件。
using System; using System.ComponentModel.Composition; namespace Parts { [Export(typeof(object))]//表示此类需要导出,导出的类型为object public class TxtFileHandler { public void Process() { Console.WriteLine("处理文本文件"); } } }
其余的就不贴了,只是类名和输出语句不同。
主程序:
using System; using System.ComponentModel.Composition.Hosting; namespace meftest { class Program { //容器,装东西用的。具体装什么先不管。 private static CompositionContainer container; static void Main(string[] args) { //AssemblyCatalog 目录的一种,表示在程序集中搜索 var assemblyCatalog = new AssemblyCatalog(typeof(Program).Assembly);//此处这一句实际上没啥用,因为此程序集下没有任何我们需要的实例(各种handler) //在某个目录下的dll中搜索。 var directoryCatalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory,"*.dll"); var aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog); //创建搜索到的部件,放到容器中。 container = new CompositionContainer(aggregateCatalog); var exports = container.GetExports<object>();//获得所有导出的部件(object类型的)。 foreach (var item in exports) { Console.WriteLine(item.Value); } Console.ReadLine(); } } }
编译两个项目,将生成的类库文件Parts.dll拷贝到主程序的bin\debug文件夹
运行主程序:
可以看到,打印出了类名(object.ToString())。我们已经成功的创建了三个类的实例,但主程序并没有引用这个类库。
也可以说,我们将类的实例成功的注入到了主程序。
从这个小例子,我们可以学到,使用MEF三步骤:1、导出所需的类型(部件),2、在合适的目录(AssemblyCatalog、DirectoryCatalog)中查找。3、将找到的部件加入到容器。
之后你就可以使用容器中的已经New好的实例了。
注意:
在TxtFileHandler这个类上面的标记[Export(typeof(object))],表示此类需要导出,而且导出的类型为object
在main函数中,var exports = container.GetExports<object>();//获得所有导出的部件(object类型的)。
导出的类型和要获得的类型必须一致,这种一致性被称作为契约。
最恨天下文章一大抄,请不要转载。