.NET 中的 Composition ,即 MEF。MEF 说得简单一点,就是它能够在运行阶段动态地发现类型,用于组件扩展方面特别合适。app
.NET Core App 的默认框架并不提供 MEF 有关的 API,但,别忘了 Nuget,那上面有相关的库,并且是官方发布的,不出意外的话,是能用的,并且老周也亲自测过,严重证明是可用的。框架
哦,是了,顺便提一下,若是你弄的是 ASP.NET Core 项目,对于组件扩展,你能够没必要考虑用 Composition,由于 ASP.NET Core 有强大的依赖注入功能,因此,经过注入,也能作到动态发现组件的效果,并且集成性更好。spa
因此,因此嘛,我们今天说的 Composition 主要是针对 .net core app,默认模板提供的是控制台应用程序,或者类库。固然了,也多是其余类型的项目,并且开源项目未来也会多起来。.net
好了,上面说的都是闲话,我们开始讲正话。code
首先,你要先建一个 core 的项目,嗯,就选控制台应用吧。component
建好项目以后,打开项目的 Nuget 管理器,搜索:对象
System.ComponentModel.Composition
注意,别搜错了,由于 System.Composition 是挺多的,能搜出一打来,可是,你要细看,System.ComponentModel.Composition 支持 Core。请注视下面这张高清无码截图。blog
如今你明白为啥要选这个了,至于说 System.Composition 是否支持在 .net core app 中使用,这个就不知道了,没试,你有空的话能够试试,但上面没有注明支持 core。接口
而后安装 System.ComponentModel.Composition 包,安装到项目后,就能用了。来,赶忙试试。get
引入如下这两个命名空间:
using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting;
定义一个接口,做为扩展组件的共同协定。
public interface IMovie { void Play(); }
它表示某电影院正在上映的电影。
下面两家影院(组件)近期比较热门。
public class NewMovie : IMovie { public void Play() { Console.WriteLine("此处正在放映《我不是酒神》"); } } public class NanMovie : IMovie { public void Play() { Console.WriteLine("此处正在放映《三烤白骨精》"); } }
其实这样定义的组件,在运行时仍是不能被发现的,咱们得让它们导出。方法是……本身看下面代码。
[Export(typeof(IMovie))] public class NewMovie : IMovie { public void Play() { Console.WriteLine("此处正在放映《我不是酒神》"); } } [Export(typeof(IMovie))] public class NanMovie : IMovie { public void Play() { Console.WriteLine("此处正在放映《三烤白骨精》"); } }
导出约束有这么几种:
* 约束类型,这通常是组件的约定接口,就是组件实现的共同接口,好比上面的 IMovie。
* 约束名,这个嘛,本身赐给它一个名字便可。
* 混合,就是约束名 + 约束类型。这种方法最为准确,在导入时能够准确找到组件。
若是 ExportAttribute 应用的目标是组件类,而不是接口类型,这时你至少得手动指定一个约束类型,设置为 IMovie,否则,它默认就是目标类的名字,这样一来,这两个组件就没法保有共同的约束,导入时不容易找出来。
我为了演示方便,我这些组件的定义与使用都是在同一个程序集中,因此,组件查找范围在当前程序集中。
// 获取当前程序集 Assembly assCurr = Assembly.GetExecutingAssembly(); // 肯定组件搜索范围 AssemblyCatalog catalog = new AssemblyCatalog(assCurr);
用上面准备好的 Catalog 去初始化 CompositionContainer ,经过容器去获取发现的组件实例。
using(CompositionContainer container = new CompositionContainer(catalog)) { // 获取已发现的组件 var components = container.GetExportedValues<IMovie>(); }
GetExportedValues 方法能直接获得全部发现的组件的实例,若是不想立刻用到组件实例,能够获取 Lazy 包装的对象,延时初始化,方法是调用 GetExports 或者 GetExport 方法。
获得全部组件实例后,能够尝试调用一下。
using(CompositionContainer container = new CompositionContainer(catalog)) { // 获取已发现的组件 var components = container.GetExportedValues<IMovie>(); // 分别调用一下 foreach(IMovie m in components) { m.Play(); } }
程序运行后,就会输出如下内容。
看,两个组件都被成功调用了。
========================================================================
最近脑细胞不够用,因此博客写得少了,老周在此表示歉意。等过一段时间,脑细胞复活了,老周有空就多写些简单实用的博文。复杂而不实用的东西老周不太会写,唉,无法了,毕竟老周的水平也比较菜,没见过大世面,没作过大项目,没调过大 bug。最大的项目也就是 1213 个实体类,200 多个存储过程,900 多个表,120 个视图。这种规模,估计是老周这一辈子作过的最大的项目了。