概述

这篇文章的目的是简要分析对比MAF和MEF,并详细举出MEF设计中的细节和扩展上的细节,达到让读者能实际操作的目的。其中,MAF的设计会附上我的代码,其实就是官方的代码我自己手动联系了一遍,但还是很有收获的,不动手光看是不会体会到细节的;MEF是我着重介绍的,当然也是微软推荐的解决方案,所以这部分内容会多一些。

至于为什么要用MEF(插件框架)读者可针对自己的项目分析是否有必要使用。

文章中难免有不足和错误,还请大家不吝指出,互相交流。

MAF和MEF

MAF是微软集成在Framework3.5中的为解决插件化编程的框架,其优势是严谨但过于死板,开发速度慢;MEF是集成在Framework4.0中新增加的,潜在的目的是替换MAF的繁琐而使开发速度增快并且适合绝大多数的工作场景,增强易用性。

下面这篇博客的作者已经对此分析的很全面了,有兴趣的请参考:

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

接口契约

无论是MAF和MEF框架均需要一个中间引用集——“契约”,插一句题外话,契约在狭义上来讲就是C#中的接口Interface,在广义上将就是一种约束,几个“部件”依赖于同一个约定来互相配合、协同,这是人类社会互相协作的精神产物。这种协同思想在软件领域也是同样适用的,包括面向服务、面向接口设计、插件化设计、代码隔离等思想。

代码分析

首先,定义契约层:定义方法和数据接口,仅仅是声明接口

namespace Practise_MEF.Contract
{
public interface ICalculator
{
String Calculate(String input);
} public interface IOperation
{
int Operate(int left, int right);
} public interface IOperationData
{
Char Symbol { get; }
} public interface IMultiOperation
{
int MultiOperate(Practise_MEF.Core.Module.InputParams p);
}
}

然后,编写服务端(Host)解析方法:服务端要定义CompositionContainer对象,此对象需要Add类别对象,包括本程序内部定义的契约实现方法(MyCalculate)和外部PlugIns目录中的接口方法。

namespace Practise_MEF
{
public class MyCalculateLoader
{
private CompositionContainer _container; [Import(typeof(ICalculator))]
public ICalculator calculator; public MyCalculateLoader()
{
//An aggregate catalog that combines multiple catalogs
var catalog = new AggregateCatalog();
//Adds all the parts found in the same assembly as the Program class
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyCalculate).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog(@"...\Output\PlugIns\")); //Create the CompositionContainer with the parts in the catalog
_container = new CompositionContainer(catalog); //Fill the imports of this object
try
{
this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
}
}

接着,实现MyCalculate契约方法、算法:

namespace Practise_MEF
{
public class MyCalculate
{
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
public class Add : IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
} [Export(typeof(IOperation))]
[ExportMetadata("Symbol", '-')]
public class Subtract : IOperation
{
public int Operate(int left, int right)
{
return left - right;
}
}
}
}

在然后,在本程序集中处理插件组方法:称为插件组是因为可能会有很多插件方法在系统的Container中,需要根据业务需求去区分应用那个插件或者全部;其中operations是系统自动导入的当前加载的插件方法集合。

namespace Practise_MEF
{
[Export(typeof(ICalculator))]
public class MyCalculateAdapter : ICalculator
{
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations; public String Calculate(String input)
{
int left;
int right;
Char operation;
int fn = FindFirstNonDigit(input); //finds the operator
if (fn < ) return "Could not parse command."; try
{
//separate out the operands
left = int.Parse(input.Substring(, fn));
right = int.Parse(input.Substring(fn + ));
}
catch
{
return "Could not parse command.";
} operation = input[fn]; foreach (Lazy<IOperation, IOperationData> i in operations)
{
if (i.Metadata.Symbol.Equals(operation))
return i.Value.Operate(left, right).ToString();
}
return "Operation Not Found!";
} private int FindFirstNonDigit(String s)
{ for (int i = ; i < s.Length; i++)
{
if (!(Char.IsDigit(s[i]))) return i;
}
return -;
} }
}

最后,在编写扩展的插件方法:

namespace Practise_MEF.Plugin.CalculateEx

{

    /// <summary>

    /// Mod

    /// </summary>

    [System.ComponentModel.Composition.Export(typeof(Practise_MEF.Contract.IOperation))]

    [System.ComponentModel.Composition.ExportMetadata("Symbol", '%')]

    public class CalculateMod : Practise_MEF.Contract.IOperation

    {

        public int Operate(int left, int right)

        {

            return left % right;

        }

    }

}

至此,一个简单、完整的插件应用已经完成,可实现动态加载处理2个数字的算法(取余),当软件需动态增加功能时,只序编写xxxxEx.dll,然后Copy到软件的PlugIns目录下即可,软件会动态增加功能。相比而言,MEF的后面隐藏和简化了更多的操作,是用户仅仅按需完成几步操作即可完成软件的插件化,使项目更灵活。

项目配置

在某个磁盘上新建一个Output文件夹,并且在Output目录下新建一个PlugIns文件夹,名称要固定,在项目中更改代码可修改名称,这不同于MAF约定过于死板。

  1. Practise_MEF项目配置

  2. Practise_MEF.Contract项目配置

  3.Practise_MEF.Core项目配置

  4.Practise_MEF.Plugin.CalculateEx项目配置

项目中需要添加项目引用 Practise_MEF.Contract.dll,其属性设置为 Copy Local 为 False 切记。

同样输出的目录为….\Output\PlugIns\,这样设置属性后,Practise_MEF.Contract.dll不会一同输出到PlugIns目录中,约束使用Practise_MEF.Plugin.CalculateEx.dll的工程中要保证有Contact.dll。

示例代码下载

引用

MAF和MEF区别:http://www.cnblogs.com/techborther/archive/2012/02/06/2339877.html

MEF官方解释:http://msdn.microsoft.com/en-us/library/dd460648.aspx

MEF分析:http://www.360doc.com/content/11/0830/16/7582031_144521508.shtml

重构笔记---MEF框架(上)的更多相关文章

  1. 重构笔记---MEF框架(下)

    概述 上一篇介绍了MEF的一个很简单很基本的应用,实现了MEF框架并展示了MEF框架的一些基本的要求和设置,这些基础知识很重要,接下来我们分析一下如何扩展或增强MEF框架内容. 增强的Contract ...

  2. C#面试题(转载) SQL Server 数据库基础笔记分享(下) SQL Server 数据库基础笔记分享(上) Asp.Net MVC4中的全局过滤器 C#语法——泛型的多种应用

    C#面试题(转载) 原文地址:100道C#面试题(.net开发人员必备)  https://blog.csdn.net/u013519551/article/details/51220841 1. . ...

  3. SpringMVC笔记——SSM框架搭建简单实例

    落叶枫桥 博客园 首页 新随笔 联系 订阅 管理 SpringMVC笔记——SSM框架搭建简单实例 简介 Spring+SpringMVC+MyBatis框架(SSM)是比较热门的中小型企业级项目开发 ...

  4. 厉害!这份阿里面试官 甩出的Spring源码笔记,GitHub上已经爆火

    前言 时至今日,Spring 在 Java 生态系统与就业市场上,面试出镜率之高,投产规模之广,无出其右.随着技术的发展,Spring 从往日的 IoC 框架,已发展成 Cloud Native 基础 ...

  5. 【山外笔记-工具框架】iperf3网络性能测试工具详解教程

    [山外笔记-工具框架]iperf3网络性能测试工具详解教程   本文下载链接 [学习笔记]iperf3网络性能测试工具.pdf 网络性能评估主要是监测网络带宽的使用率,将网络带宽利用最大化是保证网络性 ...

  6. MEF框架在Silverlight中应用(15)

    原文:MEF框架在Silverlight中应用(15) MEF框架在Silverlight中应用 代码下载 MEF框架是微软提供的一个插件框架.应用概括为一句话:输入,输出,组合.下面是具体在Silv ...

  7. SpringMVC:学习笔记(8)——文件上传

    SpringMVC--文件上传 说明: 文件上传的途径 文件上传主要有两种方式: 1.使用Apache Commons FileUpload元件. 2.利用Servlet3.0及其更高版本的内置支持. ...

  8. 笔记:FastAdmin 上传设置

    笔记:FastAdmin 上传设置 FastAdmin 的上传设置为统一配置,在 application/extra/upload.php 中文件中. <?php //上传配置 return [ ...

  9. Django:学习笔记(8)——文件上传

    Django:学习笔记(8)——文件上传 文件上传前端处理 本模块使用到的前端Ajax库为Axio,其地址为GitHub官网. 关于文件上传 上传文件就是把客户端的文件发送给服务器端. 在常见情况(不 ...

随机推荐

  1. nyoj 712 探 寻 宝 藏--最小费用最大流

    问题 D: 探 寻 宝 藏 时间限制: 1 Sec  内存限制: 128 MB 题目描述 传说HMH大沙漠中有一个M*N迷宫,里面藏有许多宝物.某天,Dr.Kong找到了迷宫的地图,他发现迷宫内处处有 ...

  2. hihocoder 1388 &&2016 ACM/ICPC Asia Regional Beijing Online Periodic Signal

    #1388 : Periodic Signal 时间限制:5000ms 单点时限:5000ms 内存限制:256MB 描述 Profess X is an expert in signal proce ...

  3. 边工作边刷题:70天一遍leetcode: day 84-2

    要点:这题是combination的应用,从左向右想比从右向左容易. 因为有结果从小到大的要求,暗示用combintion而不是permutation 其实就是从小到大验证因子,每个因子和其对称因子立 ...

  4. 边工作边刷题:70天一遍leetcode: day 84-1

    Verify preorder sequence of Binary Search Tree 要点:simulating preorder sequence: 根据preorder的特点,首先会一直向 ...

  5. js/jquery判断浏览器的方法总结

    JS获取浏览器信息浏览器代码名称:navigator.appCodeName浏览器名称:navigator.appName浏览器版本号:navigator.appVersion对Java的支持:nav ...

  6. SGU 180 Inversions

    题意:求逆序数对数量. 思路一:暴力,O(N^2),超时. 思路二:虽然Ai很大,但是n比较小,可以离散化,得到每个Ai排序后的位置Wi,然后按照输入的顺序,每个Ai对答案的贡献是Wi-Sum(Wi- ...

  7. 当文本溢出包含的元素时加省略号之text-overflow

    text-overflow是css3的属性,用来处理文本溢出,默认裁剪处理,text-overflow属性只能用于block和inline-block元素,内联的和box,flex-flow:colu ...

  8. PHP openssl加密扩展使用总结

    1.检查服务器是否已安装了openssl组件,没有则先安装好 openssl version [-a] 2.对称加密 查询openssl支持的对称加密算法 openssl_get_cipher_met ...

  9. WMI入门

    转:http://www.cnblogs.com/ceachy/archive/2013/03/21/WMI_What.html WMI入门(一):什么是WMI WMI出现至今已经二十多年了,但很多人 ...

  10. 变态跳台阶-一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

    class Solution { public: int jumpFloorII(int number) { ) ; ) ; *jumpFloorII(number-); } };