MEF的导出(Export)和导入(Import)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFDemo
{
class Program
{
[Import("MusicBook")]
public IBookService Service { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Service != null)
{
Console.WriteLine(pro.Service.GetBookName());
}
Console.Read();
} private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}

然后修改MusicBook的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
}
}

注意,标红的是改动过的地方,其他地方的代码没有变,上一次我们使用的是Export的方法是[Export(typeof(IBookService))],这次前面多了一个参数,没错,这个就是一个契约名,名字可以随便起,而且可以重复,但是如果名字乱起,和其他DLL中的重复,到时候会导致程序出现很多Bug,最好按照一定的规范去起名字。

这里有了契约名以后,导入(Import)时就要指定的契约名,否则将无法找到MusicBook,Export还有一个方法是[Export("Name")],这个方法只指定了契约名,没有指定导出类型,那么默认的导出类型是object类型,在导入时导出到的对象就要为object类型,否则将匹配不到那个组件。

到现在,我们只写了一个接口和一个实现类,导出的也是一个类,下面我们多添加几个类来看看会怎么样,为了方便大家测试,我把实现接口的类写在一个文件里面,新加几个类后,的MusicBook类文件代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
} [Export("MusicBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MathBook";
}
} [Export("MusicBook", typeof(IBookService))]
public class HistoryBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "HistoryBook";
}
} }

这里添加两个类,HistoryBook和MathBook,都继承自IBookService接口,注意他们的契约名都相同,都为MusicBook,后面再详细的说这个问题,修改后的program的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFDemo
{
class Program
{
[ImportMany("MusicBook")]
public IEnumerable<IBookService> Services { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services != null)
{
foreach (var s in pro.Services)
{
Console.WriteLine(s.GetBookName());
}
}
Console.Read();
} private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}

这里需要注意的是标红的两行代码,[ImportMany("MusicBook")]还有下面的声明变成了IEnumerable<>,因为要导出多个实例,所以要用到集合,下面采用foreach遍历输出,运行的结果如下图:

导入和导出时都不写契约名,就会全部导出。那么写契约名有什么好处呢?下面我们用代码说明问题,修改实现类的契约名如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
} [Export("MathBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MathBook";
}
} [Export("HistoryBook", typeof(IBookService))]
public class HistoryBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "HistoryBook";
}
} }

现在三个类的契约名都不相同了,其他的代码不动,再次运行程序看看,是不是现在只输出MusicBook了,同理,修改[Import("Name")]中的契约名称,就会导入指定含有名称的类,契约名可以重复,这一以来,我们就可以用契约名给类进行分类,导入时可以根据契约名来导入。

注意:IEnumerable<T>中的类型必须和类的导出类型匹配,如类上面标注的是[Exprot(typeof(object))],那么就必须声明为IEnumerable<object>才能匹配到导出的类。

例如:我们在类上面标注[Export("Book")],我们仅仅指定了契约名,而没有指定类型,那么默认为object,此时还用IEnumerable<IBookService>就匹配不到。

那么,这种情况就要在输出是进行强制类型转换,代码如下:

[Export("MusicBook")]
public class MusicBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "MusicBook";
}
}

program中的代码改变如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace MEFDemo
{
class Program
{
[ImportMany("MusicBook")]
public IEnumerable<object> Services { get; set; } static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services != null)
{
foreach (var s in pro.Services)
{
var ss = (IBookService)s;
Console.WriteLine(ss.GetBookName());
}
}
Console.Read();
} private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}

最新文章

  1. truncate表hang住(等待时间较长),出现enq:RO fast object reuse等待事件
  2. C#学习笔记---协变和逆变
  3. Js 扩展
  4. python生成器和迭代器
  5. POJ2965The Pilots Brothers&#39; refrigerator
  6. sqlserver防止数据库挂马新尝试
  7. BZOJ1978: [BeiJing2010]取数游戏 game
  8. iframe自适应高度处理方案
  9. My Stuck in C++
  10. mysql数据库死锁的产生原因及解决办法
  11. 前端知识之jQuery
  12. 强大的scrollReveal库,炫酷的页面缓入效果。
  13. PTA币值转化
  14. 使用hibernate造成的MySql 8小时问题解决方案
  15. /proc/diskstats
  16. 【论文笔记】Zero-shot Recognition via semantic embeddings and knowledege graphs
  17. [SDOI2008]洞穴勘测
  18. Echarts柱状图的点击事件
  19. opestack keystone 深入
  20. MySql检测阻塞,锁等待sql

热门文章

  1. ADC_DMA_TIM
  2. 转发: windows如何管理内存
  3. 使用Sybmol模块来构建神经网络
  4. JavaScript之DOM对象获取(1)
  5. 手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
  6. Javascript高级编程学习笔记(54)—— DOM2和DOM3(6)范围选择
  7. Java核心技术卷一基础知识-第7章-图形程序设计-读书笔记
  8. java mongodb的MongoOptions生产级配置
  9. NuGet 构建服务器与常用命令
  10. update-rc.d: error: XXX Default-Start contains no runlevels, aborting.