前言
.NET 的生態每年都在變,同一件事常常有好幾種做法。這篇整理實務上常遇到的兩個選擇:部署時要用 JIT 還是 Native AOT,以及物件映射該用手寫、AutoMapper 還是 Mapperly。
此篇文章以 .NET 8 以後的版本為主做說明。
部署架構
JIT(Just-In-Time)與 Native AOT(Ahead-Of-Time,提前編譯)的差異。
Native AOT 從 .NET 7 開始提供,但當時只支援主控台應用程式;到了 .NET 8 才支援 ASP.NET Core(Minimal API、gRPC),一般 Web API 專案要 .NET 8 以上才能使用。
| 觀點 | 一般的 JIT 執行 | Native AOT |
|---|---|---|
| 執行階段 JIT | 使用 | 不使用 |
| 發佈產物 | 以 IL中繼語言 為主 | 以原生執行檔為主 |
| 啟動 | 基準 | 相當容易改善 |
| 相容性 | 最廣 | 限制較強 |
| 動態功能 | 好用 | 限制很多 |
| 適合的目的 | 一般的 .NET 開發 | 想強力拿下啟動、散發(部署)與受限環境 |
物件映射(Object Mapping)
| 方式 | 執行效率 | 開發速度 | Debug難易度 | 編譯時期檢查 | 支援 Native AOT | 適用場景 |
|---|---|---|---|---|---|---|
| 手寫 | 極快 | 最慢 | 極易 | ✅ | ✅ | 效能要求高、欄位經常變動、或是中小型專案規模 |
| AutoMapper | 比手寫慢 | 快 | 困難 | ❌ | ❌ | AutoMapper 從 2025 年的 15 版開始改成商業授權,商用需要買授權。 |
| Mapperly | 極快 | 快 | 易 | ✅ | ✅ | 想要手寫的效能,又不想手動寫一堆 A = B 的大型專案 |
一、AutoMapper
1.註冊
services.AddAutoMapper(assemblies);
CreateMap<Model1, Model2>()
.ForMember(d => d.Age, o => o.MapFrom(s => s.age));
2.使用
private readonly IMapper _mapper;
public Test(IMapper mapper)
{
_mapper = mapper;
}
var resModel = _mapper.Map<ResModel>(resDto);
目前已知的Bug
10.1.1版以前(含),針對空值轉DateTime,會預設塞DateTime.MinValue。
但10.1.1以後的版本,針對空值轉日期,會出現 AutoMapperMappingException的錯誤。
二、Mapperly
1.設定
新增Mapper的partial class
[Mapper(PropertyNameMappingStrategy = PropertyNameMappingStrategy.CaseInsensitive)]
public partial class UserMapper
{
// 編譯器會自動實作這個方法
// 指定對應欄位
//[MapProperty(nameof(Model1.age), nameof(Model2.Age))]
public partial Model2 MapToModel2(Model1 model1);
}
備註:
(1)如果欄位對應想忽略大小寫,類別的Attribute 改成 [Mapper(PropertyNameMappingStrategy = PropertyNameMappingStrategy.CaseInsensitive)]
否則只要 [Mapper] 就好。
(2)欄位若名稱不一致,在方法的Attribute新增 MapProperty。
2.註冊
services.AddSingleton<UserMapper>();
3.從 DI取出後使用
private readonly UserMapper _userMapper;
public Test(UserMapper userMapper)
{
_userMapper = userMapper;
}
Model1 model1 = new Model1() { age = "30", assets = "1000.50", name = "John Doe", birth = "1990-01-01" };
Model2 model2 = _userMapper.MapToModel2(model1);