一、   什么是MEF

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

  我的理解:应用/插件均使用约定好的协议(接口)进行开发。系统将自动扫描指定文件夹,并按协议自动导入。

二、   MEF简单例子

1、例子一

a、定义接口

 public interface DemoOneInterface
{
void Send(string msg);
}

b、使用接口

    public class DemoOne
{
[Import]
DemoOneInterface DO; public void Run()
{
DO.Send("DemoOne.Run");
}
}
使用[Import]标记需要导入属性(DemoOneInterface DO;),如果不标记,则MEF不会进行导入。

c、创建插件类

    [Export(typeof(DemoOneInterface))]
public class DemoOneInherit1 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit1 send {0}", msg);
} #endregion
}

插件

插件类需要使用Export标记,并且声称导出类型。

d、查看效果

  static void Main(string[] args)
{
new DemoOne().Run(); Console.ReadLine();
}

原来我们使用MEF,但并没有通知MEF去寻找插件。

我们对Main函数进行修改:

var demo = new DemoOne();

            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

            //catalog.Catalogs.Add(new DirectoryCatalog("Addin"));   //遍历运行目录下的Addin文件夹,查找所需的插件。

            var _container = new CompositionContainer(catalog);

            _container.ComposeParts(demo);

            demo.Run();

修改后再次运行看看效果。

OK,运行起来了,和预期一样。

2、例子二

运行例子一,没有问题,但2个插件使用同一个的时候,会报错。

因此我们可以为Export加入别名(contractName),并且Import的时候也指定别名,MEF就会根据别名自动进行加载。

修改后代码如下:

public class DemoOne
{
[Import("")]
DemoOneInterface DO; public void Run()
{
DO.Send("DemoOne.Run");
}
} public interface DemoOneInterface
{
void Send(string msg);
} [Export("",typeof(DemoOneInterface))]
public class DemoOneInherit1 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit1 send {0}", msg);
} #endregion
} [Export("", typeof(DemoOneInterface))]
public class DemoOneInherit12 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit2 send {0}", msg);
} #endregion
}

运行效果:

3、例子三

有时我们希望一个同时使用多个插件,比如:输出log。

这时我们可以将Import改为ImportMany,并且修改Do的类型为IEnumerable<DemoOneInterface>来导入多个插件。

修改后代码:

   public class DemoOne
{
[ImportMany]
IEnumerable<DemoOneInterface> DoList; public void Run()
{
foreach (var _do in DoList)
{
_do.Send("DemoOne.Run");
}
}
} public interface DemoOneInterface
{
void Send(string msg);
} [Export(typeof(DemoOneInterface))]
public class DemoOneInherit1 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit1 send {0}", msg);
} #endregion
} [Export(typeof(DemoOneInterface))]
public class DemoOneInherit12 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit2 send {0}", msg);
} #endregion
}

运行效果:

4、例子四

现在有很多插件使用同一个约定,但我想根据配置在同一个方法中调用某个插件。

这时我们需要使用ExportMetadata来为插件的特殊属性进行标记。

使用到Lazy,来进行延迟加载,并且获取插件标记的信息。(关于Lazy具体信息请自行查找)

a、新增插件描述类

    public interface DemoOneInterfaceDepict
{
string Depict{get;}
}

b、为插件定义描述

 [Export(typeof(DemoOneInterface))]
[ExportMetadata("Depict", "")]
public class DemoOneInherit1 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit1 send {0}", msg);
} #endregion
} [Export(typeof(DemoOneInterface))]
[ExportMetadata("Depict", "")]
public class DemoOneInherit12 : DemoOneInterface
{ #region DemoOneInterface Members public void Send(string msg)
{
Console.WriteLine("DemoOneInherit2 send {0}", msg);
} #endregion
}

c、修改DoList

IEnumerable<Lazy<DemoOneInterface,DemoOneInterfaceDepict>> DoList;

d、根据配置调用

 public class DemoOne
{
[ImportMany]
IEnumerable<Lazy<DemoOneInterface,DemoOneInterfaceDepict>> DoList; public void Run()
{
foreach (var _do in DoList.Where(item=>item.Metadata.Depict == ReadXml()))
{
_do.Value.Send("DemoOne.Run");
}
} string ReadXml()
{
return "";
}
}

运行结果:

三、简化调用

上述4个例子运行正常,但我们一直没去在意Main函数里面的内容。

 var demo = new DemoOne();

            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

            //catalog.Catalogs.Add(new DirectoryCatalog("Addin"));   //遍历运行目录下的Addin文件夹,查找所需的插件。

            var _container = new CompositionContainer(catalog);

            _container.ComposeParts(demo);

            demo.Run();

看着头就晕了,难道每次构造一个函数,都这么写吗?那不是非常痛苦?!!!

重新设计一下:

1、使用基类

    public abstract class BaseClass
{
public BaseClass()
{
var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); var _container = new CompositionContainer(catalog); _container.ComposeParts(this);
}
}

修改DemoOne类继承BaseClass

 public class DemoOne : BaseClass

简化调用

 var demo = new DemoOne();
demo.Run();

运行 ok。

2、使用扩展方法

每个类都要继承这个基类,由于C#只有单继承,已经继承了一个基类后,就比较麻烦。

因此衍生出第二种方法,新增扩展方法。

扩展方法

public static class ObjectExt
{
public static T ComposePartsSelf<T>(this T obj) where T : class
{
var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog("."));
//catalog.Catalogs.Add(new DirectoryCatalog("addin")); var _container = new CompositionContainer(catalog); _container.ComposeParts(obj); return obj;
}
}

修改DemoOne类,新增构造函数,并且调用扩展方法

  public class DemoOne
{
public DemoOne()
{
this.ComposePartsSelf();
} [ImportMany]
IEnumerable<Lazy<DemoOneInterface,DemoOneInterfaceDepict>> DoList; public void Run()
{
foreach (var _do in DoList.Where(item=>item.Metadata.Depict == ReadXml()))
{
_do.Value.Send("DemoOne.Run");
}
} string ReadXml()
{
return "";
}
}

简化调用

 var demo = new DemoOne();
demo.Run();

运行 ok。

MEF学习的更多相关文章

  1. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  2. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  3. C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

    前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...

  4. C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

    上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...

  5. C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

    在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...

  6. C#可扩展编程之MEF学习

    MEF系列文章: C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import) C#可扩展编程之MEF学习 ...

  7. [转]MEF学习

    MEF学习 :http://www.cnblogs.com/comsokey/p/MEF1.html C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记( ...

  8. MEF学习笔记

    之前公司里用到了一个叫MEF的东西,说来惭愧一直只管写代码却不曾理解MEF框架为何物,今天就来学习一下,这是一篇迟到了不知多久的博客. -------------------------------- ...

  9. MEF学习小结 z

    1.什么是MEF. MEF,全称是Managed Extensibility Framework.它是.NET Framework4.0的一个类库,其主要目的是为了创建可扩展的应用程序.按照官方说法就 ...

随机推荐

  1. 在离线环境中发布.NET Core至Windows Server 2008

    在离线环境中发布.NET Core至Windows Server 2008 0x00 写在开始 之前一篇博客中写了在离线环境中使用.NET Core,之后一边学习一边写了一些页面作为测试,现在打算发布 ...

  2. 【WCF】错误协定声明

    在上一篇烂文中,老周给大伙伴们介绍了 IErrorHandler 接口的使用,今天,老周补充一个错误处理的知识点——错误协定. 错误协定与IErrorHandler接口不同,大伙伴们应该记得,上回我们 ...

  3. ASP.NET从零开始学习EF的增删改查

           ASP.NET从零开始学习EF的增删改查           最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...

  4. PHP与API讲解(一)

    了解API: 在使用与创建自己的API之前我们需要先了解什么是API! API代表应用程序编程接口,而接口指的是一个特定的服务.一个应用程序或者其他程序的公共模块. 理解SOA(面向服务的架构):SO ...

  5. 在centos7上安装Jenkins

    在centos7上安装Jenkins 安装 添加yum repos,然后安装 sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins ...

  6. jQuery可自动播放动画焦点图插件Koala

    Koala是一款简单而实用的jQuery焦点图幻灯片插件,焦点图不仅可以在播放图片的时候让图片有淡入淡出的动画效果,而且图片可以自动播放.该jQuery焦点图的每一张图片都可以设置文字描述,并浮动在图 ...

  7. javascript排序

    利用array中的sort()排序 w3cfunction sortNumber(a,b) { return a - b } var arr = new Array(6) arr[0] = " ...

  8. arcgis api for js入门开发系列八聚合效果(含源代码)

    上一篇实现了demo的图层控制模块,本篇新增聚合效果,截图如下(源代码见文章底部): 聚合效果实现的思路如下: 1.map.html引用聚合包,项目已经包含进来了的聚合文件夹: <script ...

  9. 深入理解 Android 之 View 的绘制流程

    概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...

  10. mysql 远程访问权限

    MySQL默认没有开启远程访问的权限,需要手动打开,步骤如下: 1.通过命令行登录2.mysql>update user set host = '%' where user = 'root';这 ...