MEF,是微软.net框架下的一个框架类库。可以使你的程序低耦合的加载扩展。在开发插件,或者开发一些需要灵活扩展的功能的时候经常用到。例如微软给出的计算器的例子。当你开发计算器的时候,初始功能只提供了加减功能。但后来你要扩展乘法,除法功能。显然,如果去改整个程序就会使问题变得麻烦,并且有不可预知的问题。所以微软提供给我们使用MEF来通过动态加载扩展的方法来给程序增加新功能。另外,mef,也可以用来实现依赖注入,控制反转。

我们先从最简单的DEMO开始学习mef.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection; namespace MEFDEMO
{
class Program
{
[Import]
public string Message { get; set; }
static void Main(string[] args)
{
Program program = new Program();
program.Run();
}
public void Run()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this); Console.WriteLine(Message);
Console.ReadKey();
}
}
public class SimpleHello
{
[Export]
public string Message
{
get { return "Hello World!"; }
}
}
}

这是一个最简单的例子。从上面可以看出一个简单的mef实现由下面几个部分组成

1.   一个程序用来调用的入口      [Import] public string Message { get; set; }

2.   方法的具体实现                 [Export]  public string Message{get { return "Hello World!"; }}

方法的具体实现也就是我们可以动态增加的部分。和一般的接口实现相比,通过MEF的实现使其更灵活,更易扩展。可动态添加

3.   将上面两个方法组合起来的,建立两者之间的联系。

 var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

           var container = new CompositionContainer(catalog);

           container.ComposeParts(this);


          关于如何建立两者之间的联系,在这个例子中我们是通过,获得当前程序集运行的目录,将当前目录放到一个容器中,最后通过ComposeParts(this);方法将容器container中export的方法import到实现了import特性的具体实现。我们现在来了解几个MEF中常用到的类。

ComposablePart 类:定义用于导入对象和生成已导出对象的可组合部件的抽象基类。也就是说这个类的每一个实例里面都放了里面放了一组ExportDefinitionsImportDefinitions,我们可以把每一个实例称作一个部件。

ComposablePartCatalog 类:表示收集并返回 ComposablePartDefinition 对象的可组合部件目录的抽象基类。也就是里面存放了一堆部件所在程序集的目录,注意这里不是存放了一堆部件,而是这些部件所在程序集的目录,也就是我们去找所有部件的索引项。

 ExportProvider 类:检索与指定的 ImportDefinition 对象相匹配的导出。这个类的作用很明确,就是用来寻找与 ImportDefinition 对象匹配的ExportDefinition

CompositionContainer 类:管理部件的组合。也就是用来管理ComposablePart部件的一个容器类。里面放了我们的一组组部件。注意这个类继承自ExportProvider这个类。

上面几个类是mef中抽象出来的几个类,理清这几个类的关系,我们在应用mef的时候才能高清mef的使用步骤。

下面这几个类继承自  ExportProvider 类,都能访问到相关的部件,但每一个类的侧重都不同。

System.ComponentModel.Composition.Hosting.AggregateExportProvider

检索由 ExportProvider 对象的集合提供的导出。
System.ComponentModel.Composition.Hosting.CatalogExportProvider

从目录中检索导出。                       
System.ComponentModel.Composition.Hosting.ComposablePartExportProvider

检索来自某个部件的导出。
System.ComponentModel.Composition.Hosting.CompositionContainer

侧重于管理部件,上面定义已给出。

下面这几个类继承自  ComposablePartCatalog 类,都是每个部件的存放目录,但每一个类的侧重都不同。

System.ComponentModel.Composition.Hosting.AggregateCatalog

合并 ComposablePartCatalog 对象元素的目录。
System.ComponentModel.Composition.Hosting.AssemblyCatalog

在托管代码程序集中发现特性化部件。
System.ComponentModel.Composition.Hosting.DirectoryCatalog

发现所指定目录中的程序集的特性化的部分。
System.ComponentModel.Composition.Hosting.TypeCatalog

从类型集合发现特性化部件。

其它一些类:

CompositionBatch 类:表示一组将添加至一个事务性组合的容器中或从容器中移除的 ComposablePart 对象。

ExportAttribute 类:指定某个类型、属性、字段或方法提供特定的导出。

ImportAttribute 类:指定属性、字段或参数值应由 CompositionContainer 提供。

总之,常用到的类有以上几个,还有一些其它用到的,请直接去参考msdn.

理解了上述几个类,然后我们去看我们上面的例子中将部件组合的过程。

var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

取到当前程序集运行的目录,这儿当然我们也可以去取别的程序集的目录,比如我们插件所在的扩展目录。可用如下代码去取

          

            System.ComponentModel.Composition.Hosting.AggregateCatalog category = new System.ComponentModel.Composition.Hosting.AggregateCatalog();

            foreach (var file in System.IO.Directory.GetFiles(@"C:\Users\wfm\Documents\Visual Studio 2013\Projects\WPFTest\TestReference\bin\Debug"))
{
if (file.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase))
{
try
{
var assembly = Assembly.LoadFile(file);
if (assembly == Assembly.GetCallingAssembly())
continue;
category.Catalogs.Add(new System.ComponentModel.Composition.Hosting.AssemblyCatalog(assembly));
}
catch
{
}
}
}
Container = new CompositionContainer(category, true);
this.Container.ComposeParts(this);

var container = new CompositionContainer(catalog);

这句代码创建了一个容器,创建容器很简单,这要传入一个ComposablePartCatalog类或者其子类就可以,也可以传入ExportProvider类,具体的看该方法的重载。

container.ComposeParts(this);

这里ComposeParts是一个扩展方法。调用的时候省略第一个参数。所以这里传入的this,类型:System.Object[]要组合的特性化对象的数组。也就是把这儿的[Import]  public string Message { get; set; } 传过去,然后容器就去寻找和该需要的导入对象匹配的导出对象。

在这个例子中我们是用的container.ComposeParts(this);来组合的导入导出。但是还有其他方法。例如:
      container.SatisfyImportsOnce(this);
      container.Compose(batch);
      T 实例= Container.GetExportedValue<T>();然后通过实例去调用。

本文地址:http://www.cnblogs.com/santian/p/4355730.html

博客地址:http://www.cnblogs.com/santian/

转载请以超链接形式标明文章原始出处。

MEF基础概念学习笔记的更多相关文章

  1. SpringCloud基础概念学习笔记(Eureka、Ribbon、Feign、Zuul)

    SpringCloud基础概念学习笔记(Eureka.Ribbon.Feign.Zuul) SpringCloud入门 参考: https://springcloud.cc/spring-cloud- ...

  2. oracle基础概念学习笔记

    数据库对象: 1.表:表是用来存放用户数据的对象,由行和列组成. 2.约束:保证数据完整性的规则,可以作用在耽搁字段或者多个字段组合上,用来约束这些字段上的数据必须符合作用于之上的规则. 3.视图:通 ...

  3. 操作系统概念学习笔记 10 CPU调度

    操作系统概念学习笔记 10 CPU调度 多道程序操作系统的基础.通过在进程之间切换CPU.操作系统能够提高计算机的吞吐率. 对于单处理器系统.每次仅仅同意一个进程执行:不论什么其它进程必须等待,直到C ...

  4. Java基础复习笔记系列 九 网络编程

    Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...

  5. Java基础复习笔记系列 八 多线程编程

    Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...

  6. Java基础复习笔记系列 七 IO操作

    Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ...

  7. Java基础复习笔记系列 五 常用类

    Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...

  8. Java基础复习笔记系列 四 数组

    Java基础复习笔记系列之 数组 1.数组初步介绍? Java中的数组是引用类型,不可以直接分配在栈上.不同于C(在Java中,除了基础数据类型外,所有的类型都是引用类型.) Java中的数组在申明时 ...

  9. jQuery官方基础教程笔记(转载)

    本文转载于阮一峰的博文,内容基础,结构清晰,是jquery入门不可多得的资料,非常好,赞一个. 阮一峰:jQuery官方基础教程笔记 jQuery是目前使用最广泛的javascript函数库. 据统计 ...

随机推荐

  1. Laravel 5系列教程二:路由,视图,控制器工作流程

    免费视频教程地址https://laravist.com/series/laravel-5-basic 上一篇教程我们走了那么长的路,终于把Laravel安装好了,这一篇教程我们就要进入Laravel ...

  2. flume分布式日志收集系统操作

    1.flume是分布式的日志收集系统,把收集来的数据传送到目的地去. 2.flume里面有个核心概念,叫做agent.agent是一个java进程,运行在日志收集节点. 3.agent里面包含3个核心 ...

  3. Selenium用法示例

    收录待用,修改转载已取得腾讯云授权 前言 在上一节我们学习了PhantomJS 的基本用法,归根结底它是一个没有界面的浏览器,而且运行的是 JavaScript 脚本,然而这就能写爬虫了吗?这又和Py ...

  4. Python 自用代码(某方标准类网页源代码清洗)

    用于mongodb中“标准”数据的清洗,数据为网页源代码,须从中提取: 标准名称,标准外文名称,标准编号,发布单位,发布日期,状态,实施日期,开本页数,采用关系,中图分类号,中国标准分类号,国际标准分 ...

  5. linux上MySQL改动password的各种方法,yc整理

    MySQL改动password的各种方法 整理了下面四种在MySQL中改动rootpassword的方法,可能对大家有所帮助! 方法1: 用SET PASSWORD命令 mysql -uroot my ...

  6. 一起talk C栗子吧(第二十二回:C语言实例--队列一)

    各位看官们,大家好,上一回中咱们说的是表达式求值的样例,该样例使用了栈,这一回咱们说的是栈的 兄弟:队列. 闲话休提,言归正转.让我们一起talk C栗子吧. 我们在这里说的队列是一种抽象的数据结构, ...

  7. 倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何配置虚拟轴 TC2

    右击NC- Configuration,然后Append Task,然后右击Axis,Append Axis   轴的类型可以分为:Continuous Axis,默认的类型,NC可以连续闭环控制该轴 ...

  8. Unity3D研究院之脚本生成Android Google Project

    一般安卓自动化打包直接会生成个APK出来,但是我不想生成APK,我想生成Eclipse项目. 然后在自动化完成后面的打包工作.     1 2 3 4 5 6 7 8 9 10 11 using Un ...

  9. Python课程之元组

    元组(Tuple) 一.定义: 与列表(list)不同的是,元组不支持修改,但是若元组中的元素本身是可变对象,如列表,则可以修改.元素之间用逗号隔开,并且元素的类型可以任意. 二.操作: 1.创建:直 ...

  10. Pushlet后台推送

    1.Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件:服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的 ...