MEF学习
一、 什么是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学习的更多相关文章
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
- C#可扩展编程之MEF学习笔记(三):导出类的方法和属性
前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...
- C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)
上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...
- C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo
在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...
- C#可扩展编程之MEF学习
MEF系列文章: C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import) C#可扩展编程之MEF学习 ...
- [转]MEF学习
MEF学习 :http://www.cnblogs.com/comsokey/p/MEF1.html C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记( ...
- MEF学习笔记
之前公司里用到了一个叫MEF的东西,说来惭愧一直只管写代码却不曾理解MEF框架为何物,今天就来学习一下,这是一篇迟到了不知多久的博客. -------------------------------- ...
- MEF学习小结 z
1.什么是MEF. MEF,全称是Managed Extensibility Framework.它是.NET Framework4.0的一个类库,其主要目的是为了创建可扩展的应用程序.按照官方说法就 ...
随机推荐
- NodeJs之调试
关于调试 当我们只专注于前端的时候,我们习惯性F12,这会给我们带来安全与舒心的感觉. 但是当我们使用NodeJs来开发后台的时候,我想噩梦来了. 但是也别泰国担心,NodeJs的调试是很不方便!这是 ...
- 详解树莓派Model B+控制蜂鸣器演奏乐曲
步进电机以及无源蜂鸣器这些都需要脉冲信号才能够驱动,这里将用GPIO的PWM接口驱动无源蜂鸣器弹奏乐曲,本文基于树莓派Mode B+,其他版本树莓派实现时需参照相关资料进行修改! 1 预备知识 1.1 ...
- 为C# as 类型转换及Assembly.LoadFrom埋坑!
背景: 不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有) 效果是这样的: 之后,有小部分用户反映,工具用不了(没反应或有异常)~~~ 然后,建议小部分用户换个电脑 ...
- spark处理大规模语料库统计词汇
最近迷上了spark,写一个专门处理语料库生成词库的项目拿来练练手, github地址:https://github.com/LiuRoy/spark_splitter.代码实现参考wordmaker ...
- Android消息传递之基于RxJava实现一个EventBus - RxBus
前言: 上篇文章学习了Android事件总线管理开源框架EventBus,EventBus的出现大大降低了开发成本以及开发难度,今天我们就利用目前大红大紫的RxJava来实现一下类似EventBus事 ...
- Android事件分发机制浅谈(一)
---恢复内容开始--- 一.是什么 我们首先要了解什么是事件分发,通俗的讲就是,当一个触摸事件发生的时候,从一个窗口到一个视图,再到一个视图,直至被消费的过程. 二.做什么 在深入学习android ...
- NSURLSession详解
导语 现在NSURLConnection在开发中会使用的越来越少,iOS9已经将NSURLConnection废弃,现在最低版本一般适配iOS7,所以也可以使用. NSURLConnection相对于 ...
- Atitit.软件研发团队建设原理与概论 理论
Atitit.软件研发团队建设原理与概论 理论 培训 团队文化建设(内刊,ppt,书籍,杂志等) 梯队建设 技术储备人才的问题 团队建设--小红花评比. 团队建设--文化墙.doc 户外拓展 1. 团 ...
- T-SQL 拆分使用指定分隔符的字符串(split string)
比如有一个表,我们需要些一个语句像SELECT OtherID, SplitData WHERE SomeID = 'abcdef-.......' , 然后就能返回分割成单独的行. 原表: | So ...
- grunt配置任务
这个指南解释了如何使用 Gruntfile 来为你的项目配置task.如果你还不知道 Gruntfile 是什么,请先阅读 快速入门 指南并看看这个Gruntfile 实例. Grunt配置 Grun ...