原文地址: http://www.cnblogs.com/xiaokang088/archive/2012/02/21/2361631.html
MEF 的精髓在于插件式开发,方便扩展。
例如,应用程序的日志输出到文本,后来想改为输出到数据库,按照传统的办法,需要替换项目,删除原有的引用,增加新的引用;如果使用MEF,直接用新的dll替换原来的dll,即可搞定,这就是MEF的魅力。
下面就用简单的例子来实现上述的需求。
1. 建立一个解决方案,然后增加如下的几个项目
DBlog 输出日志到数据库的实现
TextLog 输出日志到文本的实现
ILog 输出日志的接口,调用方和实现者的中间桥梁
MEFConsoleHost 控制台应用程序,模拟实用场合
MEFWPFHost WPF 应用程序,模拟实用场合
2. 先定义接口ILog,非常简单,就一个方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ILog
{
public interface ILogService
{
void Log(string content);
}
}
3. 输出到文本的实现TextLog
首先添加引用:引用刚才添加的接口Ilog 和System.ComponentModel.Composition
然后增加类TextLogService.cs,继承接口,并实现方法。
注意 类和方法都Public。
最后定义导出[Export(typeof(ILog.ILogService))]
这个是最主要的,和普通的类库区别也在这里
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel.Composition; namespace TextLog
{
[Export(typeof(ILog.ILogService))]
public class TextLogService : ILog.ILogService
{
public void Log(string content)
{
Console.WriteLine("TextLog:" + content); System.Diagnostics.TextWriterTraceListener TraceListener = new System.Diagnostics.TextWriterTraceListener(@"d:/debug.txt");
System.Diagnostics.Debug.Listeners.Add(TraceListener);
System.Diagnostics.Debug.Write(System.DateTime.Now.ToString()+" ");
Debug.Write("TextLog:" + content);
Debug.WriteLine("~~");
TraceListener.Flush();
}
}
}
4. 输出到数据库的实现DBLog,实现方法同上例,输出日志的时候区分一下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel.Composition; namespace DBLog
{
[Export(typeof(ILog.ILogService))]
public class DBLogService: ILog.ILogService
{
public void Log(string content)
{
Console.WriteLine("DBLog:" + content); System.Diagnostics.TextWriterTraceListener TraceListener = new System.Diagnostics.TextWriterTraceListener(@"d:/debug.txt");
System.Diagnostics.Debug.Listeners.Add(TraceListener);
System.Diagnostics.Debug.Write(System.DateTime.Now.ToString()+" ");
Debug.Write("DBLog:" + content);
Debug.WriteLine("");
TraceListener.Flush();
}
}
}
5. 调用方MEFConsoleHost, 这个也需要增加两个引用,
ILog 和System.ComponentModel.Composition
主程序代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFConsoleHost
{
class Program
{
[Import(typeof(ILog.ILogService))]
public ILog.ILogService CurrentLogService { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.run();
} private void run()
{
//var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory,"DbLog.dll");
var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "TextLog.dll"); var container = new CompositionContainer(catalog);
container.ComposeParts(this); CurrentLogService.Log("*MEF Log Test Pass*");
Console.Read();
}
}
}
注意两个地方
a. 导入声明
[Import(typeof(ILogService))]
public ILogService CurrentLogService { get; set; }
用接口来定义实例,然后增加导入声明,和导出的相互对应
b. 建立Catalog和Container
var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory, "TextLog.dll");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
6. 把所有项目的输出都指定到同一个目录,也就说让dll和exe在同一目录,运行控制台程序,输出
TextLog: MEF Log Test Pass
7.如果我们要输出到数据库,把上面的catalog那一句改成
var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory,"DBLog.dll");
如果不想这么麻烦,这个目录里面只放DBLog.dll 或者TextLog.dll ,然后把上面那句改为:
var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory);
照样可以用。
如果两个都在,还这么搞,那不行的,因为就定义了一个实例,同目录有两个dll。