资讯详情

AutoMapper 收费后,我对比了 Mapperly 和 Mapster:2026 年 .NET 映射库到底选谁?

📅 2026/10/15 16:41:31 | 华诺云谱 👁 阅读
AutoMapper 收费后,我对比了 Mapperly 和 Mapster:2026 年 .NET 映射库到底选谁?
先认识一下两位主角Mapperly官网https://mapperly.riok.appGitHubGitHub - riok/mapperly: A .NET source generator for generating object mappings. No runtime reflection. · GitHubNuGetRiok.Mapperly许可Apache-2.0基于 Roslyn 的源生成器编译时生成映射代码零运行时反射官方号称“比手写映射还快”。Mapster官网Mapster - The Mapper of Your Domain | Mapster - The Mapper of Your DomainGitHubGitHub - MapsterMapper/Mapster: A fast, fun and stimulating object to object Mapper · GitHubNuGetMapster许可MIT运行时编译表达式树API 极简一行AdaptT()搞定对 AutoMapper 用户迁移最友好。AutoMapper 到底怎么了简单说AutoMapper 收费了。2025 年 7 月AutoMapper转为商业授权。从 15.0 起采用双授权模式14.0.0 是最后一个 MIT 免费版本。年收入低于 500 万美元的企业可申请免费 Community 许可否则商业授权最低约489 美元/年。所以现在只有三个选择冻结在 14.0.0、付费升级、或者换库。这也是为什么值得重新看看 Mapperly 和 Mapster。两种技术路线Mapperly 是编译时生成代码。你写一个partial类声明映射方法它在编译时生成完整实现。生成的代码就是普通 C#可调试、可审查原生兼容 AOT 和裁剪。属性没映射会直接编译警告不会等到运行时才炸。csharp[Mapper] public partial class UserMapper { public partial UserDto ToDto(UserEntity user); }Mapster 是运行时编译委托。首次使用时编译表达式树并缓存默认不生成代码。功能更丰富条件映射、忽略空值、深度克隆、展平/反展平都开箱即用。也支持源生成模式但默认仍是运行时。代码对比说完了技术路线直接看代码最直观。下面用同一组模型分别展示 Mapperly 和 Mapster 的写法。模型定义假设有这样一个实体和 DTOcsharppublic class UserEntity { public int Id { get; set; } public string Name { get; set; } public DateTime BirthDate { get; set; } public string Address { get; set; } } public class UserDto { public int Id { get; set; } public string FullName { get; set; } public int Age { get; set; } }场景一基础映射属性同名同类型Mapperly定义一个partial类声明方法签名编译时自动生成实现。csharp[Mapper] public partial class UserMapper { public partial UserDto ToDto(UserEntity user); } // 调用 var mapper new UserMapper(); var dto mapper.ToDto(user);Mapster一行Adapt搞定不需要定义任何映射类。csharp// 调用 var dto user.AdaptUserDto();这是两者使用体验上最直接的差异Mapperly 要写一个空方法Mapster 连方法都不用写。场景二属性名不同需要映射配置假设UserEntity.Name要映射到UserDto.FullName。Mapperly用[MapProperty]特性标注csharp[Mapper] public partial class UserMapper { [MapProperty(nameof(UserEntity.Name), nameof(UserDto.FullName))] public partial UserDto ToDto(UserEntity user); }Mapster用TypeAdapterConfig配置配置和调用分离csharpTypeAdapterConfigUserEntity, UserDto .NewConfig() .Map(dest dest.FullName, src src.Name); // 调用 var dto user.AdaptUserDto();场景三自定义计算逻辑假设Age需要根据BirthDate计算不能直接映射。Mapperly在映射类中提供一个普通方法Mapperly 会自动发现并使用它csharp[Mapper] public partial class UserMapper { public partial UserDto ToDto(UserEntity user); private int CalculateAge(DateTime birthDate) DateTime.Today.Year - birthDate.Year; }Mapperly 在编译时发现DateTime到int有自定义方法可用就会在生成的代码中调用它。Mapster在配置中用 lambda 表达式指定映射逻辑csharpTypeAdapterConfigUserEntity, UserDto .NewConfig() .Map(dest dest.Age, src DateTime.Today.Year - src.BirthDate.Year);场景四忽略某些属性Mapperly用[MapperIgnoreSource]或[MapperIgnoreTarget]csharp[Mapper] public partial class UserMapper { [MapperIgnoreSource(nameof(UserEntity.Address))] public partial UserDto ToDto(UserEntity user); }Mapster用.Ignore()链式调用csharpTypeAdapterConfigUserEntity, UserDto .NewConfig() .Ignore(dest dest.Age);场景五映射到已有对象有时候不想创建新对象而是把值更新到已有实例上。Mapperly声明一个void返回的 partial 方法第一个参数是源对象第二个是目标对象csharp[Mapper] public partial class UserMapper { public partial void Update(UserEntity user, UserDto dto); }Mapster把目标对象作为参数传入Adaptcsharpuser.Adapt(existingDto);场景六DI 中的使用Mapperly直接注册你的partial映射类csharp// 注册 services.AddSingletonUserMapper(); // 使用 public class UserService(UserMapper mapper) { public UserDto GetUser(UserEntity user) mapper.ToDto(user); }Mapster注册IMapper接口对 AutoMapper 迁移者尤其友好csharp// 注册 services.AddMapster(); // 使用 public class UserService(IMapper mapper) { public UserDto GetUser(UserEntity user) mapper.AdaptUserDto(user); }Mapster 内置了与 AutoMapper 兼容的IMapper接口迁移期间两套代码可以共存不需要一次性替换所有调用点。一目了然的对比表对比维度MapperlyMapster基础映射写法定义partial类 方法签名一行.AdaptT()属性名映射[MapProperty]特性TypeAdapterConfig链式配置自定义逻辑普通 C# 方法自动发现lambda 表达式忽略属性[MapperIgnoreSource]等特性.Ignore()映射到已有对象void返回的 partial 方法source.Adapt(existing)DI 集成注册映射类本身注册IMapper兼容 AutoMapper编译时检查未映射属性产生编译警告默认运行时才报错生成的代码可见的.g.cs文件可直接调试默认无生成文件一句话总结Mapperly 的写法更“重”——要定义类、写方法、标特性但换来的是编译时安全和完全透明的生成代码Mapster 的写法更“轻”——一行搞定配置灵活但对运行时行为的把控不如 Mapperly 直观。性能对比早期基准中Mapperly 比手写映射快 36%Mapster 约等于手写AutoMapper 是手写的两倍多。但到了 .NET 10 时代数据变了方案耗时说明Mapperly 4.3.130.2 ns比手写映射快约 11%Mapster 10.0.1267.5 ns约手写映射的 2 倍与 AutoMapper 14 持平AutoMapper 14.0.071.9 ns—Mapster 10.x 出现了明显性能回退。7.x 时代它确实比 AutoMapper 快但 10.x 已经降到了统计上持平的水平不再有明显优势。开启 Roslyn 源生成后批量映射会改善但默认模式已经不再是性能首选。结论追求极致性能且不介意迁移成本Mapperly 是当前明确的选择。选型建议新项目默认选 Mapperly。编译时安全、零反射、AOT 兼容、性能最好。ABP 框架 v10 已经宣布从 AutoMapper 迁移到 Mapperly。涉及 Blazor WebAssembly 或 Native AOT 的项目几乎只能选它。Mapster 适合看重开发效率的项目。API 最简洁功能丰富从 AutoMapper 迁移成本最低。但要注意 10.x 的性能回退。存量 AutoMapper 项目先别急着动。如果深度依赖ProjectToT()Mapperly 和 Mapster 都没有完全等价的原生支持。可以暂时留在 14.0.0或者评估付费升级。简单场景直接手写。DTO 少于 10 个、规则简单的话手写最可控还能省一个依赖。迁移指南AutoMapper 到 Mapster低工作量安装Mapster和Mapster.DependencyInjection注册services.AddMapster()把_mapper.MapT()逐步替换为source.AdaptT()。Mapster 内置兼容IMapper两套代码可以共存。AutoMapper 到 Mapperly高工作量几乎等于重写映射层。推荐渐进式新映射先用 Mapperly再把 Profile 逐步转成[Mapper]partial 类最后移除 AutoMapper。做好心理准备这是 significant refactor 级别的工作量。写在最后AutoMapper 商业化逼着 .NET 社区重新思考一个问题对象映射到底需不需要运行时反射Mapperly 用编译时生成代码给出一个答案Mapster 用运行时编译委托给出另一个。两者不是谁更好而是谁更适合。但有一点可以确定2026 年新开的 .NET 项目已经没有必要默认选 AutoMapper 了
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑