.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]声明。
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之初体验(转)的更多相关文章
- .NET自带IOC容器MEF之初体验
.NET自带IOC容器MEF之初体验 本文主要把MEF作为一种IOC容器进行讲解,.net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuil ...
- NET 自带IOC容器MEF指初体验
转自:http://www.cnblogs.com/ulex/p/4186881.html IOC容器:工具较多,大体功能都相同,大都需要事先对接口与实现进行配对(通过代码或配置文件),然后由系统自动 ...
- .net自带的IOC容器MEF使用
IOC能做什么 IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序. 控制反转: 将控制权移交给第三方容器 new 操作 依赖注入: 在程序 ...
- 简单讲解Asp.Net Core自带IOC容器ServiceCollection
一. 理解ServiceCollection之前先要熟悉几个概念:DIP.IOC.DI.Ioc容器: 二. 接下来先简单说一下几个概念问题: 1.DIP(依赖倒置原则):六大设计原则里面一种设计原 ...
- IOC容器MEF在MVC中的使用
最近想把自己的网站框架用IOC改造下,经过对比,我初步选择autofac,虽然MEF不需要配置,但性能不行,autofac虽然需要自己写自动化注入,但性能非常好. 先分析下各大IOC框架的性能,分两类 ...
- ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自带的IOC容器)
前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...
- asp.net Core依赖注入(自带的IOC容器)
今天我们主要讲讲如何使用自带IOC容器,虽然自带的功能不是那么强大,但是胜在轻量级..而且..不用引用别的库. 在新的ASP.NET Core中,大量的采用了依赖注入的方式来编写代码. 比如,在我们的 ...
- Spring核心原理之IoC容器初体验(2)
本文节选自<Spring 5核心原理> 1 IoC与DI基本概念 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现 ...
- 【Spring专场】「IOC容器」不看源码就带你认识核心流程以及运作原理
这是史上最全面的Spring的核心流程以及运作原理的分析指南 [Spring核心专题]「IOC容器篇」不看繁琐的源码就带你浏览Spring的核心流程以及运作原理 [Spring核心专题]「AOP容器篇 ...
随机推荐
- PCB设计黄金法则永不改变
尽管目前半导体集成度越来越高,许多应用也都有随时可用的片上系统,同时许多功能强大且开箱即用的开发板也越来越可轻松获取,但许多使用案例中电子产品的应用仍然需要使用定制PCB.在一次性开发当中,即使一个普 ...
- 转--ES6 Promise 用法讲解
Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方法,原型上有then.catch等同样很眼熟的方法. 那就new一个 var p = new Promise( ...
- 《利用Python进行数据分析》笔记---第2章--来自bit.ly的1.usa.gov数据
写在前面的话: 实例中的所有数据都是在GitHub上下载的,打包下载即可. 地址是:http://github.com/pydata/pydata-book 还有一定要说明的: 我使用的是Python ...
- 8.另类方法求1+2+...+n[AnotherMethodOfCalculateSumN]
[题目] 求1+2+…+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字以及条件判断语句(A?B:C). [分析] 这道题没有多少实际意义,因为在软件开发中不 ...
- slam学习
学习内容: 数学: 线性代数,概率论, 优化理论,离散数学, 李代数, 凸优化: 算法: 概率机器人, 机器人状态估计, 深度学习,非线性优化: 工程: c/c++ , python, ros, ...
- SQLServer OpenRowSet 导入数据
今早上同事要求从SQLServer2008导出一部分数据到SQLServer2000中作为演示/测试数据,开始也没想多,直接去SQLServer2000的企业管理器中,用了数据导入的功能.以为完事了, ...
- vc 编译器的一些精典报错
本篇将平时遇到的一些编译错误 , 记录于此 , 同时帖上分析
- 百度的富文本编辑器UEDITOR
还是百度的ueditor 比较好用,文件导入后,基本不用配置就可以直接使用图片,文件上传等功能. CKeditor要注意的地方太多了 .但是相对ckeditor 样式比较好看.
- HihoCoder 1044 垃圾清理 (优化:状态压缩)
状态压缩·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市— ...
- python(十)、进程
一.基本概念 进程和线程是编程中非常重要的概念,它是并发和异步的基础性知识. 1.进程 概念:程序在并发环境中的执行过程.进程作为系统资源分配.调度.管理和独立运行的基本单位,决定了操作系统的四大特性 ...