上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容,

请阅读:http://www.cnblogs.com/yunfeifei/p/3922668.html。

  下面我们来主要讲解一下MEF中的导入和导出,还是上一篇的代码(这篇中,我还会贴出完整的代码),修改Program的代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.ComponentModel.Composition;
  7. using System.ComponentModel.Composition.Hosting;
  8.  
  9. namespace MEFDemo
  10. {
  11. class Program
  12. {
  13. [Import("MusicBook")]
  14. public IBookService Service { get; set; }
  15.  
  16. static void Main(string[] args)
  17. {
  18. Program pro = new Program();
  19. pro.Compose();
  20. if (pro.Service != null)
  21. {
  22. Console.WriteLine(pro.Service.GetBookName());
  23. }
  24. Console.Read();
  25. }
  26.  
  27. private void Compose()
  28. {
  29. var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  30. CompositionContainer container = new CompositionContainer(catalog);
  31. container.ComposeParts(this);
  32. }
  33. }
  34. }

修改MusicBook的代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel.Composition;
  6.  
  7. namespace MEFDemo
  8. {
  9. [Export("MusicBook",typeof(IBookService))]
  10. public class MusicBook : IBookService
  11. {
  12. public string BookName { get; set; }
  13.  
  14. public string GetBookName()
  15. {
  16. return "MusicBook";
  17. }
  18. }
  19. }

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

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

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel.Composition;
  6.  
  7. namespace MEFDemo
  8. {
  9. [Export("MusicBook",typeof(IBookService))]
  10. public class MusicBook : IBookService
  11. {
  12. public string BookName { get; set; }
  13.  
  14. public string GetBookName()
  15. {
  16. return "MusicBook";
  17. }
  18. }
  19.  
  20. [Export("MusicBook", typeof(IBookService))]
  21. public class MathBook : IBookService
  22. {
  23. public string BookName { get; set; }
  24.  
  25. public string GetBookName()
  26. {
  27. return "MathBook";
  28. }
  29. }
  30.  
  31. [Export("MusicBook", typeof(IBookService))]
  32. public class HistoryBook : IBookService
  33. {
  34. public string BookName { get; set; }
  35.  
  36. public string GetBookName()
  37. {
  38. return "HistoryBook";
  39. }
  40. }
  41.  
  42. }

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.ComponentModel.Composition;
  7. using System.ComponentModel.Composition.Hosting;
  8.  
  9. namespace MEFDemo
  10. {
  11. class Program
  12. {
  13. [ImportMany("MusicBook")]
  14. public IEnumerable<IBookService> Services { get; set; }
  15.  
  16. static void Main(string[] args)
  17. {
  18. Program pro = new Program();
  19. pro.Compose();
  20. if (pro.Services != null)
  21. {
  22. foreach (var s in pro.Services)
  23. {
  24. Console.WriteLine(s.GetBookName());
  25. }
  26. }
  27. Console.Read();
  28. }
  29.  
  30. private void Compose()
  31. {
  32. var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  33. CompositionContainer container = new CompositionContainer(catalog);
  34. container.ComposeParts(this);
  35. }
  36. }
  37. }

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

一共三个,都输出了,对吧!是不是很好用啊,哈哈~~

当然,如果想全部输出,可以向第一篇文章中那样,导入和导出时都不写契约名,就会全部导出。那么写契约名有什么好处呢?

下面我们用代码说明问题,修改实现类的契约名如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel.Composition;
  6.  
  7. namespace MEFDemo
  8. {
  9. [Export("MusicBook",typeof(IBookService))]
  10. public class MusicBook : IBookService
  11. {
  12. public string BookName { get; set; }
  13.  
  14. public string GetBookName()
  15. {
  16. return "MusicBook";
  17. }
  18. }
  19.  
  20. [Export("MathBook", typeof(IBookService))]
  21. public class MathBook : IBookService
  22. {
  23. public string BookName { get; set; }
  24.  
  25. public string GetBookName()
  26. {
  27. return "MathBook";
  28. }
  29. }
  30.  
  31. [Export("HistoryBook", typeof(IBookService))]
  32. public class HistoryBook : IBookService
  33. {
  34. public string BookName { get; set; }
  35.  
  36. public string GetBookName()
  37. {
  38. return "HistoryBook";
  39. }
  40. }
  41.  
  42. }

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

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

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

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

  1. [Export("MusicBook")]
  2. public class MusicBook : IBookService
  3. {
  4. public string BookName { get; set; }
  5.  
  6. public string GetBookName()
  7. {
  8. return "MusicBook";
  9. }
  10. }

program中的代码改变如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.ComponentModel.Composition;
  7. using System.ComponentModel.Composition.Hosting;
  8.  
  9. namespace MEFDemo
  10. {
  11. class Program
  12. {
  13. [ImportMany("MusicBook")]
  14. public IEnumerable<object> Services { get; set; }
  15.  
  16. static void Main(string[] args)
  17. {
  18. Program pro = new Program();
  19. pro.Compose();
  20. if (pro.Services != null)
  21. {
  22. foreach (var s in pro.Services)
  23. {
  24. var ss = (IBookService)s;
  25. Console.WriteLine(ss.GetBookName());
  26. }
  27. }
  28. Console.Read();
  29. }
  30.  
  31. private void Compose()
  32. {
  33. var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  34. CompositionContainer container = new CompositionContainer(catalog);
  35. container.ComposeParts(this);
  36. }
  37. }
  38. }

这样就可以正常运行了~~

点击这里下载源码

MEF系列文章:

C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

C#可扩展编程之MEF学习笔记(五):MEF高级进阶

C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)的更多相关文章

  1. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  2. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  3. C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

    前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...

  4. C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

    在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...

  5. C#可扩展编程之MEF学习

    MEF系列文章: C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import) C#可扩展编程之MEF学习 ...

  6. C#可扩展编程之MEF

    C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻 前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在 ...

  7. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  8. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  9. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

随机推荐

  1. tkinter 在 x window 下的字体设置格式

    X Font Descriptors # X Font Descriptors are strings having the following format (the asterisks repre ...

  2. 实战录 | 一起唠唠那些常见的DDoS攻击

    <实战录>导语 云端卫士<实战录>栏目定期会向粉丝朋友们分享一些在开发运维中的经验和技巧,希望对于关注我们的朋友有所裨益.本期分享人为云端卫士系统架构师高鹏,将带来常见的DDo ...

  3. php生成器的使用

    按照php的文档说明 一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值. 当一个生成器被调用的时候,它返回一个可以被遍历的对象.当你遍历 ...

  4. vue2 上传图片

    <template> <div class="vue-upload-img-multiple"> <div v-if="images.len ...

  5. codingNet项目的创建

    首先,在codingNet上面创建一个项目(一般情况下) 然后,在本地打开项目并添加到储存库 其次,提交代码到已经创建好的项目中(注意赋值远程存储库的路径)

  6. gitlab安装过程总结

    gitlab总算搭建好了,今天下午完成了第一个工程的导入. 梳理下搭建的过程: 1.下载bitnami的一键安装包,并安装 注意设置权限为777,以免出现某文件写入错误的问题 2.配置邮件服务 分别修 ...

  7. css大小单位px em rem的转换和详解

    css大小单位px em rem的转换和详解 PX特点1. IE无法调整那些使用px作为单位的字体大小:2. 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位:3. Firefox能 ...

  8. Fiddler 工作原理

    Fiddler工作原理: 就在在客户端与服务器端创建一个代理服务器: 在开启Fiddler后,Fiddler会自动窜改浏览器的代理,例如我们打开Fiddler,打开IE浏览器--设置--Interne ...

  9. IQD文件模板以及cs7g.ini信息

    COGNOS QUERY STRUCTURE,1,1 DATABASE, cognos TITLE,test BEGIN SQL { select time, city_id, city_name, ...

  10. centOS升级python3.5

    CentOS自带的版本是2.7.5  目前在看廖老师的教学,他给的新版本是3以上了,果断升级到最新的Python版本 (windows下面多线程里面有点问题没解决,所以才换到linux下继续学习) 一 ...