.NET自带IOC

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

  1. public class MyClass
  2. {
  3. [Import]
  4. public IMyAddin MyAddin { get; set; }
  5. }

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

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

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

发现部件

MEF提供三种方式发现部件

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

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

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

如何组合部件?

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

  1. var container = new CompositionContainer(catalog)

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

  1. container.ComposeParts(this);

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

1、         项目结构图

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

2、         METTest项目

 (1)IHelloWord.cs

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace METTest
  7. {
  8. public interface IHelloWord
  9. {
  10. string SayHello(string str);
  11. string SayWord(string str);
  12. }
  13. }

(2) HelloWord.cs

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel.Composition;
  6.  
  7. namespace METTest
  8. {
  9. [Export(typeof(IHelloWord))]
  10. internal class HelloWord:IHelloWord
  11. {
  12. public string SayHello(string str)
  13. {
  14. return "Hello" + str;
  15. }
  16. public string SayWord(string str)
  17. {
  18. return str;
  19. }
  20. }
  21. }

(3) HelloWordB.cs

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

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

4、         MEFConsoleApplication

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel.Composition;
  6. using METTest;
  7. using System.Reflection;
  8. using System.ComponentModel.Composition.Hosting;
  9. using System.IO;
  10.  
  11. namespace MEFConsoleApplication
  12. {
  13. [Export]
  14. class Program
  15. {
  16. [Import]
  17. public IHelloWord HelloWord { get; set; }
  18.  
  19. static void Main(string[] args)
  20. {
  21. Program p = new Program();
  22. p.Method();
  23. }
  24.  
  25. public void Method()
  26. {
  27. AggregateCatalog catelog = new AggregateCatalog();
  28. catelog.Catalogs.Add(new DirectoryCatalog(Directory.GetCurrentDirectory()));//查找部件,当前应用程序
  29.  
  30. //catelog.Catalogs.Add(new DirectoryCatalog(@"../../../MEFTest1/bin/Debug"));//这个我们通过路径找到部件
  31. //catelog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
  32. CompositionContainer container = new CompositionContainer(catelog);//声明容器
  33. container.ComposeParts(this);//把容器中的部件组合到一起
  34. //CompositionBatch Batch = new CompositionBatch();
  35. //Batch.AddPart(this);
  36. //container.Compose(Batch);
  37. //HelloWord = container.GetExportedValue<IHelloWord>();//这样也可以实例化借口
  38. Console.WriteLine(HelloWord.SayHello("eric"));
  39. Console.WriteLine(HelloWord.SayWord("_eric"));
  40.  
  41. Console.Read();
  42. }
  43. }
  44. }

运行结果:

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

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

  1. [ImportMany]
  2. 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();
}
}
}

本文参考:

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

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

点击下载源代码

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

 
 
 
标签: MEF

.NET自带IOC的更多相关文章

  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之初体验(转)

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

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

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

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

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

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

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

  7. 十二个 ASP.NET Core 例子——IOC

    目录 简单介绍 core自带IOC的实现解释 1.简单介绍 (个人理解) 是什么:IOC是一种设计原则,而非设计模式,是对流程控制,当你注入你需要的定制化类时,流程就确定了 怎么用:和IOC容器说你这 ...

  8. .net core3.1 下由Autofac接管IOC

    我们都知道,.net core天生自带IOC容器,但是他的功能其实并不强大,而且有坑:在构造注入的时候,他默认找参数最少的构造函数. 这里,我讲解如何使用Autofac去接管IOC,至于为什么要选Au ...

  9. IOC/DI概念简述及基本应用

    早几年面试时,面试官经常问我依赖注入的概念,但有面试官自己都不是很清楚ioc和di的区别,而是草草归于一类,今天翻了翻以前写的demo,顺便把这部分概念整理出来,加深一下印象. 先科普一下,IOC是什 ...

随机推荐

  1. linux下一个Oracle11g RAC建立(八)

    linux下一个Oracle11g RAC建立(八) 七.安装oracle软件   直接在图形界面里安装oracle.在node1操作 在虚拟机界面中,直接切换到oracle用户下: [grid@no ...

  2. C# .NET ASP.NET 其中关系你了解多少

    有些人一直在做这方面..但突然有人来问你这些问题..估计有很多答不上来. 1..NET是一个平台,一个抽象的平台的概念. .NET平台其本身实现的方式其实还是库,抽象层面上来看是一个平台. 个人理解. ...

  3. android学习8(ListView高级使用)

    ListView在android更开放的,于是继续ListView说明使用. 首先创建一个android项目,项目名为ListViewTest. ListView的简单使用 改动布局文件,改动后代码例 ...

  4. 小议 js 下字符串比较大小

    原文:小议 js 下字符串比较大小 之前群里有人问如何比较两个时间大小,他的时间格式是 2014-08-08 而不是 2014-8-8.所以我给的方法是 直接比较,如: var a = "2 ...

  5. APP-随身听

    简单到复杂听你的专属音响界,听金融.听物业,听新闻和其他节目专辑,简要介绍了新的音频应用,给你不一样的聆听体验.还记得老歌做?这里有.您留声机的一部分!很简单的音频应用,随时随地与此应用程序来听你的私 ...

  6. Java程序员应该知道的10个Eclipse调试技巧

    Eclipse是众多Java程序员实用的开发工具,其中开发技巧也是繁多,但作为优秀的Java程序员,需要掌握最起码的调试技巧. 1 条件断点 2 异常断点 3 监视点 4 评估/检查 5 修改变量值 ...

  7. C语言字符串操作函数集

    1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, n) 附加指定长度 ...

  8. c++ 正則表達式

    正則表達式是经常使用的一种方法.比較有名的类库是boost,可是这个类库在重了.全部就像找一些轻量级的类库. 后来发现准标准的库tr1已经非常方便了,微软vs2008 sp1 以上版本号都支持了.全部 ...

  9. 【剑指offer】的功率值

    标题叙述性说明: 实现函数double Power(double base, int exponent),求base的exponent次方.不得使用库函数.同一时候不须要考虑大数问题. 分析描写叙述: ...

  10. 算法回顾--N皇后问题简单回顾

    前言 最近学习的过程中,不知道哪门子的思维发散,突然又遇见皇后问题了,于是乎老调重弹,心里琢磨,虽然思路大家都容易懂,哪怕是最简单的野蛮回溯法,说着简单,但是如果非得编码实现?我可以一次性写出来OK的 ...