本文主要把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]声明。

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

修改MEFConsoleApplication项目的Program.cs

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
{
[ImportMany]
public IEnumerable<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"));
foreach (var item in HelloWord)
{
Console.WriteLine(item.SayHello("eric"));
}
Console.Read();
}
}
}

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

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

    .NET自带IOC容器MEF之初体验   本文主要把MEF作为一种IOC容器进行讲解,.net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuil ...

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

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

  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. 初用vue遇到的一些问题

    1.过滤器: filters: { search(list) { es5 var _self = this; //return list.filter(menu => menu.childs.n ...

  2. docker下的Jenkins安装和体验【转】

    原文地址:http://blog.csdn.net/boling_cavalry/article/details/78942408 作为一款优秀的持续集成工具,jenkins在日常的项目中经常会用到, ...

  3. 套接字中的recv与send的注意事项

    recv() 特征* 如果连接的另一端断开连接,则recv立即返回空子串* recv是从接受缓冲区取出内容,当缓冲区为空则阻塞* recv如果一次接受不完缓冲区内容,下次会继续接收 send() 特征 ...

  4. erlang游戏开发tcp

    之前在开发游戏的时候我们采用smartfoxserver这个java开发的游戏引擎,这个引擎在开发回合制游戏方面速度还是不错的.但是面对客户日益增长的需求还是有些力不从心.比如集群,比如灾备,热切换, ...

  5. NOI 模拟赛

    T1 Article 给 $m$ 个好串,定义一个字符串分割方案是好的当且仅当它分割出来的子串中"是好串的子串"的串长占原串串长超过 85%,定义一个好的分割方案的权值为这种分割方 ...

  6. Jmeter简单的接口测试

    1.新建线程组 2.编辑线程组信息 3.在线程组中添加HTTP信息头管理器 4.配置HTTP信息头管理器 参数格式配置 5.在线程组中添加HTTP请求 6.编辑HTTP请求信息 7.添加响应断言 8. ...

  7. 数位DP新识

    简单题:HDU2089    HDU3652  HDU4734   HDU3555  POJ3252  HigoCoder1033(需要前导0,或者用方法4) 总结: 1,dfs(pos,state, ...

  8. LOJ2611. NOIP2013 积木大赛 【线段树】

    LOJ2611. NOIP2013 积木大赛 LINK 题目大意是给你一个目标状态数组 每次你可以选择一个连续区间加上一个值,求最小操作次数 我是神奇的脑子 最近做数据结构疯了 然后看见这题就数据结构 ...

  9. 使用python处理selenium中的窗口切换问题

    # 获取当前页面的句柄 ch = self.driver.current_window_handle # 获取所有句柄 ah = self.driver.window_handles # 切换句柄 s ...

  10. Python学习-使用Python爬取陈奕迅新歌《我们》网易云热门评论

    <后来的我们>上映也有好几天了,一直没有去看,前几天还爆出退票的事件,电影的主题曲由陈奕迅所唱,特地找了主题曲<我们>的MV看了一遍,还是那个感觉.那天偶然间看到Python中 ...