【五分钟的dotnet】是一个利用您的碎片化时间来学习和丰富.net知识的博文系列。它所包含了.net体系中可能会涉及到的方方面面,好比C#的小细节,AspnetCore,微服务中的.net知识等等。
5min+不是超过5分钟的意思,"+"是知识的增长。so,它是让您花费5分钟如下的时间来提高您的知识储备量。html
一谈到如何在.Net中进行对象映射,可能大部分同窗都会脱口而出:“使用AutoMapper!”。 是的,AutoMapper 是一个很是成熟的对象映射器。截至到写这篇文章,您能在Nuget上下载到的AutoMapper包的版本为:v9.0.0,而对应的 Github 的 star 已经高达7K。git
对了,谈到AutoMapper就不得不谈起它的做者(之一):“JIMMY BOGARD”。也许您没有听过这个名字,可是您必定听过他的另外一个做品:MediatR(在微软的官方示例EShop中也使用了MediatR)。同时,“JIMMY BOGARD” 也是提出“将领域事件附加在聚合根”上的人,为领域驱动设计(DDD)作出了很大的贡献。在微软官方文档中,您能够看到该处说起到了“JIMMY BOGARD”:github
好吧,优秀的人老是优秀😭。仍是回到今天的正文,对象映射工具。固然,对于AutoMapper你们可能再熟悉不过了,并且它的知名度和热度也居高不下,看一看百度搜索结果就知道了:c#
而后再来看一看,我们今天要介绍的主角:Mapster。 不知道有多少同窗听过它?应该不多吧,这一点从百度搜索也能够看出来:app
额………………好像差距有点大哈。并且在这些搜索结果中,有用的信息只有那么几条,其中能看的文章就只有一条,并且仍是出自于博客园。 来自 “dudu” 大佬去年的一篇文章: EF Core 相关的千倍性能之差: AutoMapper ProjectTo VS Mapster ProjectToType。 再来看一看Github的状况,距离我写这一篇稿子的时候,Star数只有 518 个。框架
我们先来回顾一下AutoMapper是怎么使用的:微服务
如今有两个类,一个叫作MyEntity ,一个叫作 MyDto。 在我们书写应用层代码的时候,将数据转换为Dto是很常见的一种操做,因此这也是咱们须要对象映射器的缘由。 假设,这两个类的结构是酱紫的:工具
public class MyEntity { public string Name { get; set; } public int No { get; set; } } public class MyDto { public string Name { get; set; } public int No { get; set; } }
很广泛,也是很常见的类型。那么若是咱们要用AutoMapper来完成二者之间的转换呢?性能
var configuration = new MapperConfiguration(cfg => { cfg.CreateMap<MyEntity, MyDto>(); }); var mapper = configuration.CreateMapper(); var r = mapper.Map<MyDto>(new MyEntity() { Name = "xxx", No = 111 });
这是9.0的版本,若是您用过之前的版本可能会有点差别,好比老版本会使用Initialize方法来配置。可是思路都是同样的,也就是说,我们须要先配置对象与对象之间的相互关系,而后建立一个Mapper,在.NET core中我们通常会在Configura配置好以后,将mapper注册为一个单例,之后使用的话经过依赖注入就可使用了。学习
是的,这种写法逻辑清晰没有一点问题。那么是什么契机让我选择放弃AutoMapper呢? 可能您会认为是性能问题,毕竟在上面 dudu 的那篇文章的标题真的颇有吸引力。 但这只是很小的一部分缘由。
当我在写一些库的时候,我须要用到对象转换的功能,若是本身造轮子写一个的话也不现实(能够看看AutoMapper的源码,里面有多少的表达式树写法😞),因此我尝试引入第三方的映射工具,和你们同样我第一反应就是AutoMapper。可是在评估的时候,我发现:通常来讲,mapper对象全局只须要一个,那么这个mapper对象是在我写的库中使用,仍是交由用户来建立呢? 若是在库中建立,那么用户必须在使用库的时候进行配置,好比库公开一个委托来配置:
service.AddMyLibary(config=> { //config wrap automapper })
就比如上面的写法。可能您如今正在使用的框架中就是使用了这种方式。 固然也不是说这样很差,可是我我的感受很奇怪。
还有一点就是,AutoMapper必需要在进行了配置以后才能完成映射,若是我不提供配置的话,就是抛出一个异常。
因此,基于这两点,我就想有没有 1:简单的映射不须要配置 2:能够在任何地方进行配置 的对象映射工具。
是的,后来我采用了Mapster,很早以前就已听闻该工具,可是一直没有对比着使用过它。
若是将上面AutoMapper进行映射的代码修改一下,转换为Mapster的版本,是这样的:
var entity = new MyEntity() { Name = "xxx", No = 111 }; var r = entity.Adapt<MyDto>();
是的,没有看错,只有一句代码。(虽然我写了两句😜)。 当咱们安装了Mapster以后,object对象就会拥有一个 Adapt() 的扩展方法。只须要调用该方法就能够直接完成转换。对于简单的关系,咱们根本都不须要进行配置。
那么对于复杂的映射呢? Mapster 提供了一个 TypeAdapterConfig<T,T> 的静态泛型类型来进行配置,因此咱们能够在任何地方书写配置:
TypeAdapterConfig<MyEntity, MyDto> .NewConfig() .Map(s => s.Name, d => d.Name + "_Mapster");
就像这样,咱们就完成了这组对象的复杂映射关系。(Name里面加上"_Mapster"后缀)。
固然,上面的例子只是一个很基础的类型,可是咱们常常会遇到类型里面拥有另外的类型,这种嵌套关系能行吗? 因此咱们把上面的实体进行更改:
public class MyDto { public string Name { get; set; } public int No { get; set; } public string UoyoName { get; set; } } public class MyEntity { public string Name { get; set; } public int No { get; set; } public ChildEntity UoyoCSharp { get; set; } } public class ChildEntity { public string Name { get; set; } }
在MyEntity里面拥有一个ChildEntity的类型。 “什么?您问我为何很差好命名,好比ChildEntity就命名为Child呀,为何要命名成读不懂的东西。” 由于……您命名规范了,根本都不用写配置,Mapster会自动完成映射。 因此基于这个不规则的命名,咱们只须要进行下面的配置就好了:
TypeAdapterConfig<MyEntity, MyDto> .NewConfig() .Map(s => s.UoyoName, d => d.UoyoCSharp.Name);
就是这么简单。那么其它的高级映射呢??? 请自行跳转自文档页查询。 由于本文不是教程篇因此就偷懒了哈。固然官方的文档也不多,只须要半个小时,可能您就学完了😜。
最后,再来讲一说你们很关心的一个问题吧:它和AutoMapper比较,性能有什么差距呢? 因为选型评估的时候我也并无太考虑性能这个因素,因此就没有进行测试,可是在Github的说明页,官方给了一个测试比较:
好吧,差距相对来讲仍是挺大的。可是毕竟我没有进行确切的验证,也不会对它进行无脑吹。详细状况还请各位大佬自行测试。
最后,小声说一句:点个推荐吧.....