在物件導向的世界中,每一個階層的物件都有其定義、屬性與權限規範,因此在我們程式中常有物件與物件間的轉換。
在不使用今天介紹的工具之前,我們的程式碼很常會是這個樣子
1 | var personModel = new PersonModel |
這個東西會隨著每個階層都來一次,像是 service 層、repository 層等,會造成以下困擾:
- 程式碼又臭又長
- 阻礙閱讀
- 模糊焦點,邏輯難查
- 重複程式碼超多
- 新增一個成員變數會改到死,容易遺漏
如果你的程式碼、工作的專案有類似狀況,那 AutoMapper
這個工具將非常適合你。
測試範例
以下都會用這兩個類別來做測試的範例
1 | public class PersonDto |
在 DotNetCore 安裝
直接在 Nuget 上找到&安裝
AutoMapper.Extensions.Microsoft.DependencyInjection
註冊
AutoMapper 需要設定檔來定義哪些物件之間轉換的關係,左邊是來源、右邊是轉換的目標物件 PersonDto
-> PersonModel
1 | var mapperConfig = new MapperConfiguration(cfg => |
如果你有雙向互轉需求,也可以在後面加上 .ReverseMap()
ex: cfg.CreateMap<PersonDto, PersonModel>().ReverseMap();
使用
1 | var mapper = mapperConfig.CreateMapper(); |
宣告出 AutoMapper 物件之後,一行就能搞定,是不是很簡潔!
當然,我們實務上也不僅有單一物件需要轉換,陣列或 List 也是可以的喔!
1 | var personModels = mapper.Map<PersonModel[]>(new []{ personDto }); |
C# 除非有元素增減操作,不然我一率是推薦使用陣列
物件欄位不同怎麼辦
實務上絕對是這種狀況的,例如上面的例子就是 Model 有 FullName
欄位,但是來源的 Dto 卻只有 FirstName
與 LastName
。
這時候要使用 .ForMember
設定:
1 | cfg.CreateMap<PersonDto, PersonModel>() |
透過 ForMember
指定 FullName 是由 FirstName 與 LastName 組合而成。
建立設定檔,一勞永逸
隨著我們設定轉換的物件越來越多,總不可能都堆在邏輯層吧?
於是透過建立 Profile
的方式,將轉換用的設定檔歸類在應該要有的位置,方法很簡單,建立一個新的類別並繼承 Profie
:
1 | public class PersonProfile : Profile |
在宣告的地方加入即可,如果 Profiles 多的話,也可以考慮用 Assembly 的方式。
1 | var mapperConfig = new MapperConfiguration(cfg => |
本人,強烈建議,不要在 AutoMapper 設定中:
- 寫邏輯
- 過度使用新的邏輯語法
Conditions
,PreConditions
,NullSubstitute
很多新語法看似很方便,但會對 Trace code / Debug 造成極大的困擾,絕對是痛過才知道。
這個工具的目的是讓我們重新對焦在邏輯處,把邏輯分散就不是好事!