MEF 简介

Managed Extensibility Framework 即 MEF 是用于创建轻量、可扩展应用程序的库。 它让应用程序开发人员得以发现和使用扩展且无需配置。 它还让扩展开发人员得以轻松地封装代码并避免脆弱的紧密依赖性。 MEF 让扩展不仅可在应用程序内重复使用,还可以跨程序重复使用。

在进行传统的 C/S 端开发,如果项目不是特别复杂,常规的开发模式还是可以应对的。但是一旦场景复杂度提升,一个小小业务功能的修改就需要更新整个客户端,这个对于开发者来说是不能忍受的。因此微软为我们引入了 MEF 的开发模式。允许我们将众多的业务模块拆分开来设计成独立的 DLL,然后由客户端来进行统一加载,这样就能解决上述我们所说的痛点。

实践出真知

创建一个高扩张的 MEF 框架涉及的技术点较多。为了方便初学者能较快理解,上手实践,我这里主要通过 3 个方面来进行相关叙述。

面向接口编程

如果你还不能理解什么是面向接口编程的话,那你应该还不能区分抽象类和接口之间的区别。其实在刚开始的时候我也不是很能理解,直到我看到了一句话:抽象类规定了你是什么,接口规定了你能干什么,只要你能理解这句话,那么你应该就明白什么是面向接口编程,这种编程方式的好处是统一化了业务的暴露方式,方便外部使用。下面我们看一个简单的例子。

public interface IMessage
{
void Send();
} public class EmailService : IMessage
{
public void Send()
{
Console.WriteLine("Email Send Message");
}
} public class SMSService : IMessage
{
public void Send()
{
Console.WriteLine("SMS Send Message");
}
} class Program
{
static void Main(string[] args)
{
IMessage email = new EmailService();
email.Send(); IMessage sms = new SMSService();
sms.Send(); Console.ReadKey();
}
}

上述代码中,我们创建了一个 IPlugin 的接口,接口定义了一个 ShowPluginName() 方法,然后我们再定义了两个独立的类来分别继承该接口并实现相应的接口函数。在主函数中,我们只需要定义一个接口类型的对象,然后接收一个具体的类型实例,函数就会输出对应的正确信息。这样编程的好处就不言而喻了。代码很简单,这里就不过多描述。输出结果如下图所示

控制反转(IOC)

所谓控制反转,就是将对象初始化的控制权交出去。要实现控制反转,我们需要有面向接口编程的接口,同样的,这里也是展示一个代码段来叙述。

public interface IMessage
{
void Send();
} public class EmailService : IMessage
{
public void Send()
{
Console.WriteLine("Email Send Message");
}
} public class SMSService : IMessage
{
public void Send()
{
Console.WriteLine("SMS Send Message");
}
} public static class Factory
{
public static EmailService GetEmailService() => new EmailService(); public static SMSService GetSMSService() => new SMSService();
} class Program
{
static void Main(string[] args)
{
Console.WriteLine("DependencyService:");
DependencyService(); Console.WriteLine(); Console.WriteLine("InversionDependencyService:");
InversionDependencyService(); Console.ReadKey();
} static void DependencyService()
{
EmailService fooEmailService = new EmailService();
fooEmailService.Send();
}
static void InversionDependencyService()
{
IMessage fooMessage = Factory.GetEmailService();
fooMessage.Send();
fooMessage = Factory.GetSMSService();
fooMessage.Send();
}
}

在这个例子中,我们通过工厂模式创建具体的服务,然后供主程序来调用,代码依然很简单,分别用传统创建服务的方式和 控制反转的方式来进行对比。程序输出如下

构建入门级 MEF

有了上面两个知识点做铺垫,我们可以开始创建一个入门级的 MEF 示例程序。想要在程序中使用 MEF 的话需要引入如下程序集

  • System.ComponentModel.Composition

这里还是以控制台程序来展示。项目结构如下图所示

  • MefSample.Core:核心接口定义在该项目中
  • MefSample.EmailService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample.SMSService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample:主程序,需要引用 MefSample.Core 和 System.ComponentModel.Composition

注意:上述所有项目程序的输出目录需要保持一致

MefSample.Core 代码段

public interface IMessage
{
void Send();
}

MefSample.EmailService 代码段

[Export(typeof(IMessage))]
public class EmailService: IMessage
{
public void Send()
{
Console.WriteLine("Email Send Message");
}
}

MefSample.SMSService 代码段

[Export(typeof(IMessage))]
public class SMSService : IMessage
{
public void Send()
{
Console.WriteLine("SMS Send Message");
}
}

MefSample 代码段

class Program
{
static void Main(string[] args)
{
var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
var catalog = new DirectoryCatalog(dir.FullName, "*.dll");
using (CompositionContainer container = new CompositionContainer(catalog))
{
IEnumerable<IMessage> messages = container.GetExportedValues<IMessage>();
if (messages != null)
{
foreach (var message in messages)
{
message.Send();
}
}
}
Console.ReadKey();
}
}

仔细观察的话,其实上述代码还是挺简单的, 我这里使用了 DirectoryCatalog 的方式来寻找目标插件,感兴趣的朋友可以试试其他方式:AggregateCatalogAssemblyCatalogDirectoryCatalog。当然,你也可以自定义。程序输出结果如下图所示

好了,程序写到这里相信你对 MEF 也多少有些了解。我没有过多的讲解抽象理论,而是更多地通过代码来描述我所想要说的。在下篇文章中,我将会简单讲述一下 MEF 在 WPF 中的入门使用,方便初学者更上一层楼。加油,共勉!

相关参考

MEF 插件式开发之 小试牛刀的更多相关文章

  1. MEF 插件式开发 - 小试牛刀

    原文:MEF 插件式开发 - 小试牛刀 目录 MEF 简介 实践出真知 面向接口编程 控制反转(IOC) 构建入门级 MEF 相关参考 MEF 简介 Managed Extensibility Fra ...

  2. MEF 插件式开发 - WPF 初体验

    原文:MEF 插件式开发 - WPF 初体验 目录 MEF 在 WPF 中的简单应用 加载插件 获取元数据 依赖注入 总结 MEF 在 WPF 中的简单应用 MEF 的开发模式主要适用于插件化的业务场 ...

  3. [MEF插件式开发] 一个简单的例子

    偶然在博客园中了解到这种技术,顺便学习了几天. 以下是搜索到一些比较好的博文供参考: MEF核心笔记 <MEF程序设计指南>博文汇总 先上效果图 一.新建解决方案 开始新建一个解决方案Me ...

  4. [转][MEF插件式开发] 一个简单的例子

    偶然在博客园中了解到这种技术,顺便学习了几天. 以下是搜索到一些比较好的博文供参考: MEF核心笔记 <MEF程序设计指南>博文汇总 先上效果图 一.新建解决方案 开始新建一个解决方案Me ...

  5. MEF 插件式开发之 WPF 初体验

    MEF 在 WPF 中的简单应用 MEF 的开发模式主要适用于插件化的业务场景中,C/S 和 B/S 中都有相应的使用场景,其中包括但不限于 ASP.NET MVC .ASP WebForms.WPF ...

  6. MEF 插件式开发之 DotNetCore 中强大的 DI

    背景叙述 在前面几篇 MEF 插件式开发 系列博客中,我分别在 DotNet Framework 和 DotNet Core 两种框架下实验了 MEF 的简单实验,由于 DotNet Framewor ...

  7. MEF 插件式开发之 DotNetCore 初体验

    背景叙述 在传统的基于 .Net Framework 框架下进行的 MEF 开发,大多是使用 MEF 1,对应的命名空间是 System.ComponentModel.Composition.在 Do ...

  8. 也来学学插件式开发续-利用MEF

    前面一个博客:也来学学插件式开发中很多朋友留言说可以用MEF来实现.于是我就试着用MEF实现了一下. 步骤和上一篇差不多,只是加载插件的方式有所不同.这只是一个自己的示例程序,肯定有很多不足之处,欢迎 ...

  9. C#学习笔记-----基于AppDomain的"插件式"开发

    很多时候,我们都想使用(开发)USB式(热插拔)的应用,例如,开发一个WinForm应用,并且这个WinForm应用能允许开发人员定制扩展插件,又例如,我们可能维护着一个WinService管理系统, ...

随机推荐

  1. UART串口通讯协议

    一.UART定义 UART 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种通用的串行异步全双工数据收发传输器(总 ...

  2. cf 700e(sam好题,线段树维护right)

    代码参考:http://blog.csdn.net/qq_33229466/article/details/79140428 #include<iostream> #include< ...

  3. 微信小程序之自定义模态弹窗(带动画)实例

    1.基本需求. 实现用户自定义弹框 带动画(动画可做参靠,个人要是觉得不好看可以自定义动画) 获取弹出框的内容,自定义事件获取 2.案例目录结构 二.程序实现具体步骤 1.弹框index.wxml代码 ...

  4. redis 分布式读写锁

    http://zhangtielei.com/posts/blog-redlock-reasoning.html 链接里这篇 blog 讨论了 redis 分布式锁的实现以及安全性 我要参考 基于单R ...

  5. Struts2再爆远程命令执行漏洞![W3bSafe]Struts2-048 Poc Shell及防御修复方案抢先看!

    漏洞概述 Apache Struts是美国阿帕奇(Apache)软件基金会负责维护的一个开源项目,是一套用于创建企业级Java Web应用的开源MVC框架.在Struts 2.3.x 系列的 Show ...

  6. kubernetes集群搭建(6):kubernetes基本使用演示

    以简单部署访问来演示kubernetes的基本使用 流程: 用户访问client应用,client应用中调用server应用,由于部署了多节点,client在访问server时应该配置server 暴 ...

  7. IDEA中读取 resource目录下文件

    1. 资源文件 2. 加载文件 public void test() { try { System.out.println("begin test"); String filepa ...

  8. python中使用双端队列解决回文问题

    双端队列:英文名字:deque (全名double-ended queue)是一种具有队列和栈性质的抽象数据类型. 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两边进行. 双端队列可以在 ...

  9. Python——collections模块

    collections模块 collections模块在内置数据类型(dict.list.set.tuple)的基础上,还提供了几个额外的数据类型:ChainMap.Counter.deque.def ...

  10. c++编程之内存的分配

    当我们在进行编程时,特别是使用c++语言进行编程时,需要知道内存有几个内存区可供我们使用,因为c++可以直接操作内存.接下让我们来看看内存中的几大内存区. 1.栈区 栈区(stack)是速度最快的一个 ...