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. JavaScript 图片弹框显示

    function fnCreate(src) {             /* 要创建的div的classname */             var ClassName = "thumb ...

  2. Kafka安装与配置(windows)

    作者:灬花儿灬 出处:http://www.cnblogs.com/flower1990/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则 ...

  3. js实现带上传进度的文件上传

    //获取文件筐的文件集合 var files = document.getElementById("file1").files; //创建FormData对象 相当于参数集合 存储 ...

  4. [android] xml文件的序列化

    生成xml文件,模拟备份短信,创建短信的业务bean,创建一个domain的包放业务bean,这个业务bean里面,定义成员属性,生成get set方法,生成有参和无参的构造方法. 生成随机数,实例化 ...

  5. 阿里云oss,简单上传

    描述:oss比较方便,省去了自己搭建文件服务器的时间,价格比较便宜,下面是java基于oss的简单上传代码 a.添加maven依赖 <dependency> <groupId> ...

  6. JSJ——java基本概念一

    Java曾以什么优点吸引你走上程序员这条不归路? 友好的语法.面向对象.内存管理和最棒的跨平台可移植性.write-once/run-anywhere 当然,只有我们真正投身入java才发现有bug要 ...

  7. 表单时间和定时器this的指向

    1.针对表单的 form 表单  input 输入框 select 下拉列表  textarea 文本域 type 类型 radio 单选框 checkbox 多选框 password 密码框 but ...

  8. youtube link for review STAT(1)

    Confidence Interval: https://www.youtube.com/watch?v=bekNKJoxYbQ Introduction to confidence interval ...

  9. endpoint 异常

    原文地址:http://blog.csdn.net/ltylove2007/article/details/6128333 其他信息: 无法加载协定为“ServiceReference1.WebSer ...

  10. 一位ML工程师构建深度神经网络的实用技巧

    一位ML工程师构建深度神经网络的实用技巧 https://mp.weixin.qq.com/s/2gKYtona0Z6szsjaj8c9Vg 作者| Matt H/Daniel R 译者| 婉清 编辑 ...