一般情况下,我们对系统要求:

1.对扩展开发对修改关闭

2.高层模块不应该依赖于低层模块,应该依赖于抽象

实际上,这是遵循了面向对象的设计原则中的开放封闭原则和依赖倒置原则,其所做的事情就是为了提高系统的可扩展能力和对代码解耦。

为了满足上述的要求,我们引用了微软的MEF框架,让他来帮助我们做这些事情。

一、概念

  MEF (Managed Extensibility Framework) 使开发人员能够在其 .NET 应用程序中提供挂钩,以供用户和第三方扩展。可以将 MEF 看成一个通用应用程序扩展实用工具。

  MEF 使开发人员能够动态创建扩展,无需扩展应用程序,也不需要任何特定于扩展内容的知识。这可以确保在编译时两者之间不存在耦合,使应用程序能够在运行时扩展,不需要重新编译。MEF 还可以在将扩展加载到应用程序之前,查看扩展程序集的元数据,这是一种速度更快的方法。

二、原理

  将被我们特殊标记的方法,属性,字段,类型,导入到一个容器中,我们再通过MEF内置的反射来使用容器中被我们导入的各种方法,属性,字段,类型。

三、示例

1.类型

public interface IDBConn
{void Conn();
}[Export("SqlConn", typeof(IDBConn))]
 public class SqlConn : IDBConn{public void Conn(){Console.WriteLine("this is SqlServer connection");}}

  我们的数据库连接可能会是多种连接,如果我们直接写死为SqlServer的连接,显然不符合开放关闭原则,所以我们提供了一个数据库连接的接口IDBConn,然后用SqlServer的连接SqlConn ,去实现数据库连接接口。

  然后利用MEF中的Export将该类型导出至MEF的容器中。

  调用:

public string Test()
{
    // 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
    Container.ComposeParts();//获得容器中的ExportIDBConn _conn = IOCContainer.Container.GetExportedValue<IDBConn>("SqlConn");_conn.Conn();return "";
}    

  这是我们的一种方式,当我们的导出到容器中的类过于庞大的时候,我们可以换一种方式来获得导出。

  MEF提供Lazy加载,Lazy的好处在于,我们可以先声明,到了需要使用的时候才会实际去加载,代码如下:

public string TestLazy(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();//lazyvar export =Container.GetExport<IDBConn>("SqlConn");IDBConn _conn = export.Value;_conn.Conn();return "";}

  到此,我们类型说的就差不多了,但是似乎有一点小问题,如果我需要根据某些特定的东西来判断加载哪个类型怎么办?

  首先,我们先看下Export的定义:

        //// 摘要://     通过在指定协定名称下导出指定类型,初始化 System.ComponentModel.Composition.ExportAttribute 类的新实例。//// 参数://   contractName://     用于导出使用此特性标记的类型或成员的协定名称,或 null 或空字符串 ("") 以使用默认协定名称。////   contractType://     要导出的类型。public ExportAttribute(string contractName, Type contractType);   

  使用contractName可以满足这个需求,但是MEF提供了更加优雅的方式----元组。

  代码如下:

public interface IDBConnMetadata{string Version { get; }}[Export("SqlConn", typeof(IDBConn))][ExportMetadata("Version", "v1.0.1")]public class SqlConn : IDBConn{public void Conn(){Console.WriteLine("this is SqlServer connection");}}public string TestMetadata(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();var export = Container.GetExports<IDBConn, IDBConnMetadata>();//筛选version为v1.0.1的IDBConn _conn = export.Where(p => p.Metadata.Version.Equals("v1.0.1")).FirstOrDefault().Value;_conn.Conn();return "";}

  到此类型就完全ok了,接下来看一下方法。

2.方法

  方法需要对匿名委托需要有一些了解,不懂的,可以自行查一下,很简单。

public class MySqlConn : IDBConn{private MySqlConn(){}[Export("Conn", typeof(Action))]public void Conn(){Console.WriteLine("this is MySqlConn connection");}[Export("GetStr", typeof(Func<string>))]private string GetStr(){ return "随便试试字符串"; }[Export("GetLength", typeof(Func<string, int>))]public int GetLength(string str){return str.Length;}}

  等一下,上面代码是不是有问题啊?构造方法是私有的,也没有用单例,这怎么调用啊?

  首先这又不是静态方法,不能用类名.方法名的方式调用,并且不能实例化,这样岂不是很蒙圈。

  那么我们试着用MEF写一下调用,代码如下:

public string TestAction(){TestActionNoPara();TestActionWithPara();TestActionWithParaAndReturn();return "";}#region  Import Action#region Import 无参无返回方法private void TestActionNoPara(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();var action = Container.GetExport<Action>("Conn");action.Value.Invoke();}#endregion#region Import 无参有返回方法private void TestActionWithPara(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();var action = Container.GetExport<Func<string>>("GetStr");string message = action.Value.Invoke();}#endregion#region Import 有参有返回方法private void TestActionWithParaAndReturn(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();var action = Container.GetExport<Func<string, int>>("GetLength");int length = action.Value.Invoke("GetLength");}#endregion#endregion

  完全可以访问,并没有因为私有构造方法而造成不能访问,并且上面的GetStr方法也是私有的,依旧可以访问。

  这就恶心了,方法的访问修饰符完全被MEF破坏了。。。

  感觉这应该算一个bug吧,不过MEF提供了一个属性,可以让方法或者类不能被使用[PartNotDiscoverable]。

3.属性和字段

  研究了好久也不知道这个属性和字段应该应用到哪里,有什么实际的应用场景,不过,还是写下这个怎么用。

[Export("SqlConn", typeof(IDBConn))]public class SqlConn : IDBConn{[Export("Description")]public string Description { get { return "this is SqlServer connection"; } }public void Conn(){Console.WriteLine("this is SqlServer connection");}}

public string TestAttribute(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();var desc = Container.GetExportedValue<string>("Description");return desc;}//字段[Import("SqlConn")]private IDBConn dbConn;

4.构造方法注入

  我们也可以用构造方法的方式完成注入,代码如下:

#region 构造注入[Export("TestB")]public class TestB{private IDBConn _conn;[ImportingConstructor]public TestB([Import("SqlConn")]IDBConn conn){_conn = conn;}public bool IsInject(){if (_conn == null){return false;}else{return true;}}}#endregionpublic string TestInject(){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//创建容器var Container = new CompositionContainer(assemblyCatalog);//执行组合
            Container.ComposeParts();var x = Container.GetExportedValue<TestB>("TestB");bool result = x.IsInject();return result.ToString();}

四、改进

  上面就是MEF的一些基本使用方法,但是写了这么久发现了似乎有一点问题啊。

  每次调用都去创建目录,创建容器,执行组合,似乎太繁琐了,而且重复这些操作,明显也会浪费资源,所以我们可以做一下改进,将这些重复步骤提炼出来一个单独的方法,供其他方法调用。

  

public class IOCContainer{public static CompositionContainer Container { get; private set; }private static IOCContainer instance = new IOCContainer();private IOCContainer(){if (Container == null){//AssemblyCatalog:表示从程序集中搜索部件的目录// 创建一个程序集目录,用于从一个程序集获取所有的组件定义var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());//指定加载某个程序集//var directoryCatalog = new DirectoryCatalog("要加载dll的路径");//AggregateCatalog:聚合目录,可以添加上面所说的所有目录,从而进行多方面的部件搜索//var aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog);//创建容器Container = new CompositionContainer(assemblyCatalog);//container = new CompositionContainer(aggregateCatalog);//container.GetExportedValue//执行组合
                Container.ComposeParts();}}public static IOCContainer RegisterContainer(){return instance;}}

  写好了容器,我们可以在Global.asax中调用RegisterContainer方法,其他使用容器的地方,改为IOCContainer.Container.GetExport就ok了,既简化了代码,也节约了资源。

  到这里MEF的总结,就全部完成了,欢迎交流。

转载于:https://www.cnblogs.com/Yuuuuu/p/9198017.html

MEF(可扩展框架)使用总结相关推荐

  1. .NET MEF托管可扩展框架

    MEF简介: 今天学习了下MEF框架,MEF,全称Managed Extensibility Framework(托管可扩展框架).MEF是专门致力于解决扩展性问题的框架,MSDN中对MEF有这样一段 ...

  2. MEF-(Managed Extensibility Framework)托管可扩展框架

    目录 MEF简介: 实例 实例1 例子2 总结一下MEF框架的好处: Demo 下载 MEF简介: 今天学习了下MEF框架,MEF,全称Managed Extensibility Framework( ...

  3. php扩展的框架,新一代轻量级PHP扩展框架 Asf

    一.Asf 是什么? 全称 API Services Framework, 用C语言编写的轻量级PHP扩展框架, 专注于 API 开发. 二.解决了什么问题? 2.1 把复杂的逻辑简单化(降低错误率, ...

  4. IBM发布Open Liberty 18.0.0.4,支持MicroProfile 2.1和反应性扩展框架

    IBM在2018年第四季度发布的Open Liberty 18.0.0.4提供了对MicroProfile 2.1.反应性扩展框架和连接池指标的全面支持.根据发布说明: Open Liberty现在对 ...

  5. Asp.net 面向接口可扩展框架之类型转化基础服务

    新框架正在逐步完善,可喜可贺的是基础服务部分初具模样了,给大家分享一下 由于基础服务涉及面太广,也没开发完,这篇只介绍其中的类型转化部分,命名为类型转化基础服务,其实就是基础服务模块的类型转化子模块 ...

  6. Asp.net 面向接口可扩展框架之核心容器

    新框架的容器部分终于调通了!容器实在太重要了,所以有用了一个名词叫"核心容器". 容器为什么那么重要呢?这个有必要好好说道说道. 1.首先我们从框架名称面向接口编程说起,什么是面向 ...

  7. windows phone7 学习笔记14——地理位置服务与反应性扩展框架

    使用Location Service能帮助开发者为windows Phone 开发具备位置感知(Location-Aware)功能的应用程序.比如很多导航的软件,查找附近吃饭.娱乐甚至厕所的应用程序, ...

  8. 2、生成一个PHP扩展框架

    女主宣言 今天小编为大家分享编写PHP扩展的系列文章,文章从环境构建到扩展编写,会对使用到的相关PHP内核数据结构及API进行介绍,希望能对大家有所帮助. PS:丰富的一线技术.多元化的表现形式,尽在 ...

  9. c php 速度,CSpeed: CSpeed 框架,全堆栈的轻量级C语言PHP扩展框架,以高性能、极速为目标。...

    CSpeed v2.0.0 高性能扩展框架-只为追求极致的速度 CSpeed v2.0.0 新架构 一个简单的WEB应用入口: $app = new \Cs\App("../app/conf ...

  10. Chrome扩展框架-浏览器插件安装方法

    Chrome扩展框架系列文章 本人是一个web前端开发工程师,主要是vue框架,整理了一些Chrome扩展,今后也会一直更新,有好建议的同学欢迎评论区分享讨论 ;-) Chrome扩展专栏:点击此处 ...

最新文章

  1. url获取网站信息不包含网页源文件内的标签_前嗅ForeSpider链接抽取应用场景及链接在源码的html标签里写脚本...
  2. 如何获取shell脚本中某条语句的执行时间
  3. PHPRunner中文版
  4. Linux下SSH使用rsa认证方式省去输入密码
  5. 仓库中应用的计算机设备有哪些,智能仓储设备系统中有哪些常见的应用工具
  6. Java集合中removeIf的使用
  7. java线程——中断线程+线程状态+线程属性(优先级)
  8. 使用jquery操作iframe
  9. Redis读写分离技术解析
  10. EclipseIDE常用快捷键
  11. UVA11361 Investigating Div-Sum Property
  12. 狄斯奎诺算法 c语言,图的邻接表实现迪杰斯特拉算法(C语言)
  13. fread与fread_s读取文件(二进制文件)
  14. Django框架详细介绍---认证系统
  15. 6.函数基础和函数参数
  16. linux怎么查看tudexo状态,linux怎么安装tuxedo中间件?
  17. 微信商城制作的步骤是什么?微信商城模板大全
  18. C语言写一个猜数字游戏?我只想玩王者荣耀
  19. 三层交换机与路由器对接上网配置示例
  20. 成长三部曲(一):成长的底层逻辑

热门文章

  1. windows doc快捷键
  2. spring断言使用
  3. MySQL筛选重复数据
  4. Linux下chkconfig命令介绍
  5. Android OpenGL ES 应用(二) 纹理
  6. 运动后肌肉酸痛怎么办?
  7. 【C#学习笔记】单精度和双精度浮点型操作留意。
  8. 迷你计算机笔记本,迷你笔记本电脑我选择了它,性能不错还超轻便携
  9. FPGA状态机跑飞原因分析
  10. 水经注叠加cad_如何下载等高线并在CAD中与卫星影像叠加