1、什么是MEF

先来看msdn上面的解释:MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。

也有人把MEF解释为“依赖注入”的一种方式,那么什么是“依赖注入”?如果这样解释,感觉越陷越深......根据博主的理解,了解MEF只需要抓住以下几个关键点:

(1)可扩展的framework,或者叫可扩展的库。也就是说,使用MEF是为了提高程序的可扩展性。MEF会根据指定的导入导出自动去发现匹配的扩展,不需要进行复杂的程序配置。

(2)在设计层面上来说,为什么要使用MEF?为了“松耦合”!我们知道,程序设计有几个原则,“高内聚,低耦合”就是其中一个。使用MEF可以帮助我们减少内库之间的耦合。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFDemo
{
class Program
{
[Import("MusicBook")]
public IBookService Service { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Service != null)
{
Console.WriteLine(pro.Service.GetBookName());
}
Console.Read();
}
private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
修改MusicBook的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MusicBook";
}
}
}
注意,标红的是改动过的地方,其他地方的代码没有变,上一次我们使用的是Export的方法是 [Export(typeof(IBookService))] ,这次前面多了一个参数,没错,这个就是一个契约名,名字可以随便起,而且可以重复,但是如果名字乱起,和其他DLL中的重复,到时候会导致程序出现很多Bug,最好按照一定的规范去起名字。
这里有了契约名以后,导入(Import)时就要指定的契约名,否则将无法找到MusicBook,Export还有一个方法是 [Export("Name")], 这个方法只指定了契约名,没有指定导出类型,那么默认的导出类型是object类型,在导入时导出到的对象就要为object类型,否则将匹配不到那个组件。
到现在,我们只写了一个接口和一个实现类,导出的也是一个类,下面我们多添加几个类来看看会怎么样,为了方便大家测试,我把实现接口的类写在一个文件里面,新加几个类后,的MusicBook类文件代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MusicBook";
}
}
[Export("MusicBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MathBook";
}
}
[Export("MusicBook", typeof(IBookService))]
public class HistoryBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "HistoryBook";
}
}
}
这里添加两个类,HistoryBook和MathBook,都继承自IBookService接口,注意他们的契约名都相同,都为MusicBook,后面再详细的说这个问题,修改后的program的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFDemo
{
class Program
{
[ImportMany("MusicBook")]
public IEnumerable<IBookService> Services { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services != null)
{
foreach (var s in pro.Services)
{
Console.WriteLine(s.GetBookName());
}
}
Console.Read();
}
private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
这里需要注意的是标红的两行代码,[ImportMany("MusicBook")]还有下面的声明变成了IEnumerable<>,因为要导出多个实例,所以要用到集合,下面采用foreach遍历输出,运行的结果如下图:
一共三个,都输出了,对吧!是不是很好用啊,哈哈~~
当然,如果想全部输出,可以向第一篇文章中那样,导入和导出时都不写契约名,就会全部导出。那么写契约名有什么好处呢?
下面我们用代码说明问题,修改实现类的契约名如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
namespace MEFDemo
{
[Export("MusicBook",typeof(IBookService))]
public class MusicBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MusicBook";
}
}
[Export("MathBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MathBook";
}
}
[Export("HistoryBook", typeof(IBookService))]
public class HistoryBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "HistoryBook";
}
}
}
现在三个类的契约名都不相同了,其他的代码不动,再次运行程序看看,是不是现在只输出MusicBook了,同理,修改[Import("Name")]中的契约名称,就会导入指定含有名称的类,契约名可以重复,这一以来,我们就可以用契约名给类进行分类,导入时可以根据契约名来导入。
注意 : IEnumerable<T>中的类型必须和类的导出类型匹配,如类上面标注的是[Exprot(typeof(object))],那么就必须声明为IEnumerable<object>才能匹配到导出的类。
例如:我们在类上面标注[Export("Book")],我们仅仅指定了契约名,而没有指定类型,那么默认为object,此时还用IEnumerable<IBookService>就匹配不到。
那么,这种情况就要在输出是进行强制类型转换,代码如下:
[Export("MusicBook")]
public class MusicBook : IBookService
{
public string BookName { get; set; }
public string GetBookName()
{
return "MusicBook";
}
}
program中的代码改变如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFDemo
{
class Program
{
[ImportMany("MusicBook")]
public IEnumerable<object> Services { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services != null)
{
foreach (var s in pro.Services)
{
var ss = (IBookService)s;
Console.WriteLine(ss.GetBookName());
}
}
Console.Read();
}
private void Compose()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}

属性、方法、字段等都是可以注入的

如有疑问,请加群568055323联系群主。

C#进阶のMEF注入的更多相关文章

  1. MEF 注入[转载]

    领域服务的时候,用到MEF的注入有参构造函数的方法,your master was attracted,打算稍微深挖一下,这篇来对此知识点做个总结. 一.知识点回顾 MEF作为IOC的方式之一,它的主 ...

  2. C#进阶系列——DDD领域驱动设计初探(一):聚合

    前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...

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

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

  4. ASP.NET 5:依赖注入

    ASP.NET 5:依赖注入 1.背景 如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口.简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程. 那么问题来了?如何选择客户 ...

  5. 20145308 《网络对抗》 注入shellcode+Return-to-libc攻击 学习总结

    20145308 <网络对抗> 逆向及BOF进阶实践 注入shellcode+Return-to-libc攻击 学习总结 实践目的 注入shellcode 实现Return-to-libc ...

  6. DDD领域驱动设计初探(一):聚合

    前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...

  7. DDD领域驱动设计初探

    DDD领域驱动设计初探1 前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下D ...

  8. WPF prism 类、属性和方法的导入和导出

    学习Prism一定要掌握依赖注入的应用,只有了解了Prism的依赖注入才能更好的使用Prism提升应用开发的架构. 首先说明Prism依赖注入有两种方式及MEF和Unity ,在Prism中是两个没有 ...

  9. C#进阶系列——MEF实现设计上的“松耦合”(四):构造函数注入

    前言:今天十一长假的第一天,本因出去走走,奈何博主最大的乐趣是假期坐在电脑前看各处堵车,顺便写写博客,有点收获也是好的.关于MEF的知识,之前已经分享过三篇,为什么有今天这篇?是因为昨天分享领域服务的 ...

随机推荐

  1. Netty实战七之EventLoop和线程模型

    简单地说,线程模型指定了操作系统.编程语言.框架或者应用程序的上下文中的线程管理的关键方面.Netty的线程模型强大但又易用,并且和Netty的一贯宗旨一样,旨在简化你的应用程序代码,同时最大限度地提 ...

  2. Syncrhonized 和 Lock的区别和使用

    相信很多小伙伴们初学多线程的时候会被这两个名词搞晕,所以这里专门介绍这两种实现多线程锁的方式的区别和使用场景 Synchronized 这个关键词大家肯定都不陌生,具体的用法就是使用在对象.类.方法上 ...

  3. Java五种基本的Annotation,提高程序的可读性

    从JDK5开始,Java增加了对元数据的支持,也就是Annotation(即注解也被翻译为注释). 这里的Annotation和普通的注释有一定的区别,它是代码中的特殊标记,这些标记可以在编译.类加载 ...

  4. Java中重写与重载

    重写(覆盖):发生在子类与父类之间:方法名相同方法的个数.类型相同返回值类型小于等于父类的返回值类型 重载:发生在一个类中:方法名相同方法的个数.类型不同返回值类型可以相同也可以不相同

  5. CSS3动画:流彩文字效果+图片模糊效果+边框伸展效果实现

    前言 首先第一步,先布局html代码如下: <div class="wrap"> <img src="images/1.jpg" class= ...

  6. jQuery计算文本宽度和input标签根据输入字符动态自适应宽度的实现

    jQuery计算文本宽度的原理是利用html提供的<pre>标签,向dom中动态添加<pre>标签,标签里的内容就是要测试长度的文本,获取完长度之后再删除刚才添加的<pr ...

  7. 【代码笔记】Web-JavaScript-JavaScript 条件语句

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  8. [ORACLE]ORA-28002 The password will expire within 7 days.将不能登录系统

    错误“ORA-28002 The password will expire within 7 days.  Cannot logon to the database“当在进程调度器上运行AE程序可能遇 ...

  9. Tars http服务

    http服务 发布到平台后可以直接使用 http 请求来调用,注意发布服务时选择 非 tars 协议! 1,创建一个 springboot 项目,并在启动类添加 @EnableTarsServer 注 ...

  10. Testlink1.9.17使用方法(第九章 测试结果分析)

    第九章 测试结果分析 QQ交流群:585499566 TestLink根据测试过程中记录的数据,提供了较为丰富的度量统计功能,可以直观的得到测试管理过程中需要进行分析和总结的数据.点击首页横向导航栏中 ...