【五分鐘的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的說明頁,官方給了一個測試比較:
好吧,差距相對來講仍是挺大的。可是畢竟我沒有進行確切的驗證,也不會對它進行無腦吹。詳細狀況還請各位大佬自行測試。
最後,小聲說一句:點個推薦吧.....