.NET自带IOC容器MEF之初体验

 

本文主要把MEF作为一种IOC容器进行讲解,.net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuilder,StructureMap,Spring.Net等,这些第三方工具各不相同,但功能大体都相同,大都需要事先对接口与实现进行配对(通过代码或配置文件),然后由系统自动或手动来通过接口来获得相应实现类的实例,对象实例化的工作由IOC容器自动完成。

概述   

官方说法: Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)等。MEF为开发人员提供了一个工具,让我们可以轻松的对应用程序进行扩展并且对已有的代码产生最小的影响,开发人员在开发过程中根据功能要求定义一些扩展点,之后扩展人员就可以使用这些扩展点与应用程序交互;同时MEF让应用程序与扩展程序之间不产生直接的依赖,这样也允许在多个具有同样的扩展需求之间共享扩展程序。

解决的问题    

MEF解决了什么呢?以往,如果一个应用程序需要支持插件方式必须要实现自己的底层并且这些插件通常是针对特有应用的,不能被其他应用所使用。实际上MEF提供了发现和组合的能力使你的应用程序可以加载扩展,为运行时的可扩展性提供了一种简单的解决方法:  MEF为宿主应用提供了一种标准的途径来暴露自身并使用外部扩展。而扩展本身是可以被不同的应用程序所使用的。而一个扩展依旧可以通过针对特定应用的方法来实现。扩展之间也可以存在依赖关系,MEF则会自动将它们按照正确的顺序进行调用。MEF还提供了一些用来定位和加载可用扩展的方法。MEF允许使用附加元数据对扩展进行标记,从而达到易于丰富的查询和筛选的目的。

工作原理

简短说一下MEF的工作原理,MEF的核心包括一个catalog和一个CompositionContainer。category用于发现扩展,而container用于协调创建和梳理依赖性。每个可组合的Part提供了一个或多个Export,并且通常依赖于一个或多个外部提供的服务或Import。每个Part管理一个实例为应用程序运行

MEF 提供一种通过“组合”隐式发现组件的方法。 MEF 组件(称为“部件-Part”)。部件以声明方式同时指定其依赖项(称为“导入-Import”)及其提供的功能(称为“导出-Export”)。MEF原理上很简单,找出有共同接口的导入、导出。然后找到把导出的实例化,赋给导入。说到底MEF就是找到合适的类实例化,把它交给导入。

如何声明一个部件-导入与导出

导出”是部件向容器中的其他部件提供的一个值,而“导入”是部件向要通过可用导出满足的容器提出的要求。 在特性化编程模型中,导入和导出是由修饰类或成员使用 Import 和Export 特性声明的。 Export 特性可修饰类、字段、属性或方法,而 Import 特性可修饰字段、属性或构造函数参数。为了使导入与导出匹配,导入和导出必须具有相同的协定。

假设有一个类MyClass,它声明了可以导入插件的类型是IMyAddin。

public class MyClass
{
[Import]
public IMyAddin MyAddin { get; set; }
}

这里有一个类,它声明为导出。类型同样为IMyAddin。

[Export(typeof(IMyAddin))]
public class MyLogger : IMyAddin { }

这样我们使用MyAddin属性的时候就可以获得到MyLogger的实例。

发现部件

MEF提供三种方式发现部件

  • AssemblyCatalog 在当前程序集发现部件。
  • DirectoryCatalog 在指定的目录发现部件。
  • DeploymentCatalog 在指定的XAP文件中发现部件(用于silverlight)

当通过不同方式发现部件的时候,还可以使用AggregateCatalog来把这些部件聚合到一起。

var catalog = new AggregateCatalog();
//把从Program所在程序集中发现的部件添加到目录中
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
//把从指定path发现的部件添加到目录中
catalog.Catalogs.Add(new DirectoryCatalog("C:\\Users\\v-rizhou\\SimpleCalculator\\Extensions"));

如何组合部件?

在加载完部件之后,要把它们放到一个CompositionContainer容器中。

var container = new CompositionContainer(catalog)

通过调用容器的ComposeParts()方法可以把容器中的部件组合到一起。

container.ComposeParts(this);

下面我们使用一个简单的列子学习使用MEF

1、         项目结构图

注:三个项目都要添加System.ComponetModel.Composition.dll的引用。

2、         METTest项目

 (1)IHelloWord.cs

为我们定义的接口,只有两个简单方法,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace METTest
{
public interface IHelloWord
{
string SayHello(string str);
string SayWord(string str);
}
}

(2) HelloWord.cs

该文件继承IHelloWord接口并实现接口中的方法,HelloWord类被声明成internal防止方法在类外被引用,用[Export(typeof(IHelloWord))]修饰声明该类为导出,类型为IHelloWord,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition; namespace METTest
{
[Export(typeof(IHelloWord))]
internal class HelloWord:IHelloWord
{
public string SayHello(string str)
{
return "Hello" + str;
}
public string SayWord(string str)
{
return str;
}
}
}

(3) HelloWordB.cs

该文件先不用看,下面用到了在做说明

3、         METTest1项先不管,下面用到了在做说明

4、         MEFConsoleApplication

该项目为控制台项目,添加对METTest的引用,不要添加对METTest1项目的引用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using METTest;
using System.Reflection;
using System.ComponentModel.Composition.Hosting;
using System.IO; namespace MEFConsoleApplication
{
[Export]
class Program
{
[Import]
public IHelloWord HelloWord { get; set; } static void Main(string[] args)
{
Program p = new Program();
p.Method();
} public void Method()
{
AggregateCatalog catelog = new AggregateCatalog();
catelog.Catalogs.Add(new DirectoryCatalog(Directory.GetCurrentDirectory()));//查找部件,当前应用程序 //catelog.Catalogs.Add(new DirectoryCatalog(@"../../../MEFTest1/bin/Debug"));//这个我们通过路径找到部件
//catelog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
CompositionContainer container = new CompositionContainer(catelog);//声明容器
container.ComposeParts(this);//把容器中的部件组合到一起
//CompositionBatch Batch = new CompositionBatch();
//Batch.AddPart(this);
//container.Compose(Batch);
//HelloWord = container.GetExportedValue<IHelloWord>();//这样也可以实例化借口
Console.WriteLine(HelloWord.SayHello("eric"));
Console.WriteLine(HelloWord.SayWord("_eric")); Console.Read();
}
}
}

运行结果:

5、下面我们来看一下一个接口被多个类实例化

当一个接口被多个类实例化时,用ImportMany 声明,具体如下

[ImportMany]
public IEnumerable<IHelloWord> HelloWord { get; set; }

打开HelloWordB.cs文件继承IHelloWord,并用[Export(typeof(IHelloWord))]修饰。这样HelloWord和HelloWordB都继承了IHelloWord,并且用[Export]声明。

修改MEFConsoleApplication项目的Program.cs

本文参考:

http://wenku.baidu.com/view/abc72ec80508763231121273.html

http://www.cnblogs.com/techborther/archive/2012/02/06/2339877.html

点击下载源代码

每天学习一点点,每天进步一点点。

.NET自带IOC容器MEF之初体验的更多相关文章

  1. NET 自带IOC容器MEF指初体验

    转自:http://www.cnblogs.com/ulex/p/4186881.html IOC容器:工具较多,大体功能都相同,大都需要事先对接口与实现进行配对(通过代码或配置文件),然后由系统自动 ...

  2. .NET自带IOC容器MEF之初体验(转)

    本文主要把MEF作为一种IOC容器进行讲解,.net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuilder,StructureMap,Spri ...

  3. .net自带的IOC容器MEF使用

    IOC能做什么 IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序. 控制反转: 将控制权移交给第三方容器  new 操作 依赖注入: 在程序 ...

  4. 简单讲解Asp.Net Core自带IOC容器ServiceCollection

    一.  理解ServiceCollection之前先要熟悉几个概念:DIP.IOC.DI.Ioc容器: 二.  接下来先简单说一下几个概念问题: 1.DIP(依赖倒置原则):六大设计原则里面一种设计原 ...

  5. IOC容器MEF在MVC中的使用

    最近想把自己的网站框架用IOC改造下,经过对比,我初步选择autofac,虽然MEF不需要配置,但性能不行,autofac虽然需要自己写自动化注入,但性能非常好. 先分析下各大IOC框架的性能,分两类 ...

  6. ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自带的IOC容器)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  7. asp.net Core依赖注入(自带的IOC容器)

    今天我们主要讲讲如何使用自带IOC容器,虽然自带的功能不是那么强大,但是胜在轻量级..而且..不用引用别的库. 在新的ASP.NET Core中,大量的采用了依赖注入的方式来编写代码. 比如,在我们的 ...

  8. Spring核心原理之IoC容器初体验(2)

    本文节选自<Spring 5核心原理> 1 IoC与DI基本概念 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现 ...

  9. 【Spring专场】「IOC容器」不看源码就带你认识核心流程以及运作原理

    这是史上最全面的Spring的核心流程以及运作原理的分析指南 [Spring核心专题]「IOC容器篇」不看繁琐的源码就带你浏览Spring的核心流程以及运作原理 [Spring核心专题]「AOP容器篇 ...

随机推荐

  1. 最短路径算法之三——Bellman-Ford算法

    Bellman-Ford算法 Dijkstra算法无法判断含负权边的图的最短路. 如果遇到负权,在没有负权回路存在时,即便有负权的边,也可以采用Bellman-Ford算法正确求出最短路径. PS:负 ...

  2. 8款JS框架比较

    Dojo     Dojo 是目前最为强大的JS框架,它在自己的 Wiki 上给自己下了一个定义,Dojo 是一个用 JavaScript 编写的开源的DHTML工具箱.Dojo 很想做一个“大一统” ...

  3. PHP Apache Access Log 分析工具 拆分字段成CSV文件并插入Mysql数据库分析

    现在需要分析访问日志,怎么办? 比如分析D:\Servers\Apache2.2\logs\access2014-05-22.log http://my.oschina.net/cart/针对这个问题 ...

  4. postgresql 行转列,拼接字符串

    create table k_user ( op_id ) not null, op_name ) not null, password ) not null, real_name ) not nul ...

  5. HTML5 jQuery图片上传前预览

    hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该file的url,一个空的img标签,ID为img0,把选择 ...

  6. 一个可能是pip的一个BUG

    今天重新安装了Python,把Python的安装位置改为 D:\Program Files\Python\Python34\ 用pip 安装 Django 的时候出现一下错误 >pip inst ...

  7. 动态加载dll--不占用文件

    Assembly assembly = Assembly.Load(path); 用上面的方法可以动态的加载到dll,但是用这种方法加载到的dll一直到程序运行结束都是占用的,在此期间不能够对此进行升 ...

  8. uva11992-Fast Matrix Operations(区间增值、改值)

    题意: r行c列的全0矩阵   有三种操作 1 x1 y1 x2 y2 v子矩阵(x1,y1,x2,y2)所有元素增加v 2 x1 y1 x2 y2 v子矩阵(x1,y1,x2,y2)所有元素设为v ...

  9. USB HID报告及报告描述符简介

    在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等.USB报告描述符(Report Descriptor)是HID ...

  10. bzoj 3263 陌上花开(cdq分治,BIT)

      [题意] 求满足Ai<=Aj,Bi<=Bj,Ci<=Cj的数对的数目. [思路] cdq分治 借网上一句话:第一维排序,第二维cdq分治,第三维树状数组维护. 首先合并三维都是相 ...