.NET Core 和 .NET Framework 中的 MEF2
MEF,Managed Extensibility Framework,现在已经发布了三个版本了,它们是 MEF 和 MEF2。
等等!3 去哪儿了?本文将教大家完成基于 MEF2 的开发。
MEF 和 MEF2
其实微软发布了四个版本的 MEF:
- 随着 .NET Framework 4.0 发布,微软称之为 MEF
- 随着 .NET Framework 4.5 发布,微软让它更好用了,微软称之为 MEF2,但因为接口兼容,也直接称之为 MEF
- .NET 开发团队觉得 MEF 第一代性能太差,于是通过 NuGet 为移动设备发布了可移植类库,是个轻量级版本,只移植了 .NET Framework 中 MEF2 里 2 的部分;随后 .NET Core 中也加入了 MEF2,也是 .NET Framework 中 MEF2 里 2 的部分
- Visual Studio 开发团队觉得 .NET Framework 里的 MEF2 性能太差,NuGet 版的 MEF2 功能太少,于是自己又写了一个,微软称之为 VS-MEF
对于第一代的 MEF,我们这里就完全不说了,性能又差功能又少,没有利用价值。
对于 .NET Framework 4.5 里引入的 MEF2,性能上没能改进多少,倒是使用起来功能更多。详细资料和使用方法请参考微软官方的文档:
- Managed Extensibility Framework (MEF) - Microsoft Docs
- Attributed Programming Model Overview (MEF) - Microsoft Docs
而本文主要说的 MEF2 是微软后来以 NuGet 包形式发布的 MEF2;适用于 .NET Framework 4.5 及以上、.NET Core 和各种 .NET 移动平台。它的接口相比于 .NET Framework 中原生带的已经变了,中文和英文的参考资料很少,几乎都是参考微软官方发布的文档才能使用。所以本文将为大家提供其中文的使用方法指导。
至于性能提升程度,我没有进行定量测试,所以直接从 IoC Container Benchmark - Performance comparison - www.palmmedia.de 一文中搬运了性能测试结果,如下:
安装 MEF2
.NET Framework 中自带的 MEF 在程序集 System.ComponentModel.Composition.dll 中,命名空间为 System.ComponentModel.Composition
。MEF2 随 NuGet 包发布,其 NuGet 包名是 Microsoft.Composition,命名空间为 System.Composition
。
所以,在需要使用 MEF2 的项目中安装以上 NuGet 包即可完成安装。
使用 MEF2 开发
MEF 完全使用特性来管理容器中的依赖,微软称之为 Attributed Programming Model,并辅以广告——不需要配置文件的依赖注入容器。所以,使用特性来标记依赖关系就成了 MEF 的招牌依赖管理方式。
使用方法我将分为两个部分来讲,最容易的是业务代码,给开发团队中所有成员使用的代码。比较难的是框架代码,给开发团队中写框架的那一部分成员。
业务代码
业务代码的写法其实取决于框架开发者怎么去定义框架。但是,为了方便大家理解,在这一节我将只说 MEF2 最原生的使用方法。框架那一节我才会说明如何自定义业务代码的写法。
最原生的使用方法其实只有两个——[Import]
和 [Export]
,其它都是变种!具体说来,标记了 Export
的类将导出给其它类使用;标记了 Import
的属性/字段/方法参数等将接收来自 Export
的那些类/属性/字段的实例。
Import/Export
在类型上标记 [Export]
可以让容器发现这个类型。[Export]
允许带两个参数,一个契约名称,一个契约类型。在 [Import]
的时候,相同的契约名称会被注入;与属性或字段的类型相同的契约类型会被注入。
IEnumerable/Lazy
如果属性或字段是集合类型,可以使用 [ImportMany] 来注入集合(如果 Export
有多个)。
如果属性或字段是 Lazy<T>
类型,那么并不会立即注入,而是在访问到 Lazy<T>.Value
时才获取到实例(如果此时的创建过程由容器处理,那么第一次访问 Value
时才会创建)。
框架代码
框架代码也分为两个部分:一个部分是初始化,初始化后可以创建一个依赖注入容器;另一个部分是管理依赖,将使用之前初始化好的依赖注入容器进行管理。
初始化的最简代码如下:
var compositionHost = new ContainerConfiguration().CreateContainer();
那么,得到的 compositionHost 变量将是用来管理依赖的容器,你可以将它储存在字段中用于随后管理依赖。
但是,只是这么初始化将得不到任何对象。所以,我们需要额外添加配置代码,以便将一些程序集中的对象添加到容器中:
var compositionHost = new ContainerConfiguration().WithAssemblies(new []
{
typeof(A).Assembly,
typeof(B).Assembly,
typeof(C).Assembly,
typeof(D).Assembly,
}).CreateContainer();
这样,A/B/C/D 这四个类分别所在的程序集中,直接或间接加了 [Export]
特性的类都将被此依赖容器管理。
MEF2 之所以为 2,因为它除了能通过 [Export]
特性导出,还能直接在框架中发现而不必由业务开发者手动指定。这在第三方代码或者不希望被 MEF 侵入的代码中非常有用。例如,我们将所有已有的 ViewModel 导出:
// 使用 ConventionBuilder 自动导出所有的 ViewModel。
var convention = new ConventionBuilder();
// 将所有继承自 ViewModelBase 的类导出,并共享一个实例(即注入到多个属性中的都是同一个实例)。
convention.ForTypesDerivedFrom<ViewModelBase>().Export().Shared();
// 使用这些配置创建依赖注入容器。
var compositionHost = new ContainerConfiguration().WithAssemblies(new []
{
typeof(A).Assembly,
typeof(B).Assembly,
typeof(C).Assembly,
typeof(D).Assembly,
}).WithDefaultConventions(convention).CreateContainer();;
注意,以上代码中的 .Shared()
目的是让导出的 ViewModel
共享实例(同一个类型的实例只有一个)。
只初始化是不行的,还需要将这些依赖注入到目标实例中才行。使用 SatisfyImports
可以将传入的对象中的所有依赖注入进去。
compositionHost.SatisfyImports(targetObject);
在框架设计中,对于不同模块中的类型,框架需要决定使用哪一个容器来注入,或者是否注入。所以上面这个代码会发生在使用 MEF2 框架中需要注入的任何一个部分。
参考资料
- MEF in .NET 4.5 - CodeProject
- Managed Extensibility Framework(MEF) 2 框架新特性介绍 - PetterLiu - 博客园
- Is MEF or MEF2 baked into the .NET Framework? - Stack Overflow
- vs-mef/why.md at master · Microsoft/vs-mef
- mef/Home.md at master · MicrosoftArchive/mef
.NET Core 和 .NET Framework 中的 MEF2的更多相关文章
- [UWP小白日记-11]在UWP中使用Entity Framework Core(Entity Framework 7)操作SQLite数据库(一)
前言 本文中,您将创建一个通用应用程序(UWP),使用Entity Framework Core(Entity Framework 7)框架在SQLite数据库上执行基本的数据访问. 准备: Enti ...
- .NET Core中延迟单例另一种写法【.NET Core和.NET Framework的beforefieldinit差异】
1.BeforeFieldInit是什么 前段时间在反编译代码时无意间看到在类中有一个BeforeFieldInit特性,处于好奇的心态查了查这个特性,发现这是一个关于字段初始化时间的特性[提前初始化 ...
- .NET Core与.NET Framework、Mono之间的关系
随着微软的.NET开源的推进,现在在.NET的实现上有了三个.NET Framework,Mono和.NET Core.经常被问起Mono的稳定性怎么样,后续Mono的前景如何,要回答这个问题就需要搞 ...
- .NET Core 和 .NET Framework 之间的关系
引用一段描述:Understanding the relationship between .NET Core and the .NET Framework. .NET Core and the .N ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 创建复杂数据模型
Creating a complex data model 创建复杂数据模型 8 of 9 people found this helpful The Contoso University sampl ...
- .Net Core vs .Net Framework 如何为一个应用程序选择一个运行时
.Net Core是下一件大事吗?我已经使用了一段时间了,我倾向认为它是.事实上,我们推测,在2018年,对这项技术熟练的开发人员将会有巨大的需求.但是它和.Net Framework的区别是什么?你 ...
- 在.NET Framework中慎用DirectoryInfo.GetFiles方法
.NET Framework中的DirectoryInfo.GetFiles方法,可以在一个文件夹下通过通配符找出符合条件的文件. 我们首先在文件夹C:\DemoFolder下定义两个文件:demo. ...
- 一场关于 .net core 和 .net framework 编码的案情分析
案情背景 目前公司做新项目,基本所有新项目都是用.net core来做,旧项目一半还是基于 .net framework下面,一半已经迁移到了core平台.在做新项目的时候,有个功能需要对接到旧项目那 ...
- .Net Core vs .Net Framework 如何为一个应用程序选择一个运行时(翻译)
.Net Core是下一件大事吗?我已经使用了一段时间了,我倾向认为它是.事实上,我们推测,在2018年,对这项技术熟练的开发人员将会有巨大的需求.但是它和.Net Framework的区别是什么?你 ...
随机推荐
- $.extendGit 丢弃所有本地修改的方法
git checkout . #本地所有修改的.没有的提交的,都返回到原来的状态 git stash #把所有没有提交的修改暂存到stash里面.可用git stash pop回复. git rese ...
- ScrambleString, 爬行字符串,动态规划
问题描述: Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty su ...
- BZOJ4767 两双手
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- FlatBuffer入门笔记
FlatBuffer入门笔记 1 flatbuffer资料 flatbuffer下载地址:https://github.com/google/flatbuffers flatbuffer官方使用文档: ...
- spring mvc: 可参数化的视图控制器(在配置中指定jsp文件)MultiActionController/SimpleUrlHandlerMapping/ParameterizableViewController
spring mvc: 可参数化的视图控制器(在配置中指定jsp文件)MultiActionController/SimpleUrlHandlerMapping/ParameterizableView ...
- selenium常用API实例
1.访问网页地址 driver.get( url ); driver.navigate( ).to( url ); 2.访问网页前进.后退 driver.navigate( ).forward( ); ...
- IP地址分类、私有地址、子网、子网掩码
IP地址分类介绍 这里讨论IPv4,IP地址分成了A类.B类.C类.C类.E类,如下图所示: 解释: A类以0开头,网络地址有7位,主机地址有24位,举例:A类地址:0 10000000 000000 ...
- zoj4028 LIS,差分约束
题意:给你以i为结尾的最长上升子序列的值,和每个值的区间范围求可行的a[i] 题解:差分约束,首先满足l[i]<=a[i]<=r[i],可以建一个虚拟节点n+1,那么有a[n+1]-a[i ...
- Log4j详细设置说明
1. 动态的改变记录级别和策略,即修改log4j.properties,不需要重启Web应用,这需要在web.xml中设置一下.2. 把log文件定在 /WEB-INF/logs/ 而不需要写绝对路径 ...
- httplib模块,测试cdn节点文件同步
httplib模块是一个专门用于http的模块,urllib和urllib2也都是基于对它进行了更上层次的封装 我记得刚开始的时候,公司用的cdn有段时间抽风,全球40多个节点总是有那么几个节点不同步 ...