Mapster 构造函数映射指南:用 ConstructUsing 与 MapToConstructor 掌控目标对象创建
Mapster 构造函数映射指南用 ConstructUsing 与 MapToConstructor 掌控目标对象创建【免费下载链接】MapsterA fast, fun and stimulating object to object Mapper项目地址: https://gitcode.com/GitHub_Trending/ma/MapsterMapster 默认通过无参构造函数创建目标对象但在实际项目中DTO 常常只暴露带参构造函数、依赖工厂方法或需要对象初始化器来预置默认值。本文基于 Mapster 的ConstructUsing与MapToConstructor两大配置项完整讲解如何接管目标对象的创建过程、如何按构造函数参数自动映射、以及如何显式指定特定构造函数并给出仓库源码级的实现佐证帮助你写出可复制、可运行的映射配置。目录一、默认创建方式的局限二、用 ConstructUsing 自定义目标对象创建无参构造函数场景非默认构造函数场景对象初始化器场景带 destination 参数的重载三、用 MapToConstructor 映射到构造函数全局默认开启类型对级别开启自定义构造函数参数映射Pascal case多构造函数时如何自动选择显式指定 ConstructorInfo四、源码级原理剖析构造工厂在 Settings 中的存储构造函数选择算法无默认构造函数时的错误提示五、典型实战场景映射到接口类型搭配 AfterMapping 使用 destination 重载六、相关文档与测试一、默认创建方式的局限Mapster 的核心Adapt操作在创建目标对象时默认期望目标类型具备无参构造函数empty constructor。在 BaseAdapter.cs 中当目标类型没有默认构造函数时会抛出如下异常No default constructor for type {arg.DestinationType.Name}, please use ConstructUsing or MapWith这说明 Mapster 本身已经内置了两种解决方案ConstructUsing自定义创建逻辑或MapWith整体替换映射逻辑。本文聚焦前者并延伸到相关的MapToConstructor配置。此外默认情况下 Mapster只会映射到字段和属性fields and properties构造函数参数并不在默认映射范围内。要让映射结果直接通过构造函数注入需要使用MapToConstructor显式开启。二、用 ConstructUsing 自定义目标对象创建ConstructUsing允许你提供一个函数调用来创建目标对象而不是使用默认的无参对象创建方式。该函数返回一个目标类型的实例你可以调用自己的构造函数、工厂方法或任何能产出期望类型对象的代码。无参构造函数场景当目标对象创建不需要源对象参与时使用无参重载TypeAdapterConfigTSource, TDestination.NewConfig() .ConstructUsing(() new TDestination());对应源码位于 TypeAdapterSetter.cspublic TypeAdapterSetterTDestination ConstructUsing(ExpressionFuncTDestination constructUsing) { this.CheckCompiled(); Settings.ConstructUsingFactory arg constructUsing; return this; }可以看到ConstructUsing接受的是表达式树ExpressionFunc...而非普通委托这意味着它会被内联进 Mapster 编译生成的映射表达式中而不是作为外部委托调用从而不影响映射性能。非默认构造函数场景最典型的用法是调用目标类型的非默认构造函数从源对象取参//Example using a non-default constructor TypeAdapterConfigTSource, TDestination.NewConfig() .ConstructUsing(src new TDestination(src.Id, src.Name));源码中对应的是带源对象参数的重载位于 TypeAdapterSetter.cspublic TypeAdapterSetterTSource, TDestination ConstructUsing(ExpressionFuncTSource, TDestination constructUsing) { Settings.ConstructUsingFactory arg constructUsing; return this; }仓库测试 WhenUsingNonDefaultConstructor.cs 验证了这一行为即使目标类型同时具备无参构造函数配置了ConstructUsing后映射仍会走自定义构造函数且Unmapped属性被赋值为传入的固定值unmapped同时Id、Name等可映射成员依旧正常映射。对象初始化器场景你同样可以使用对象初始化器object initializer预置某些目标对象自己的成员值//Example using an object initializer TypeAdapterConfigTSource, TDestination.NewConfig() .ConstructUsing(src new TDestination{Unmapped unmapped});这种写法在 WhenUsingNonDefaultConstructor.cs 的Dest_Calls_Calls_Factory_Method_With_ConstructUsing测试中也有对应验证。需要注意ConstructUsing的表达式体在投影Projection场景下只支持New和MemberInit两种节点类型。在 ClassAdapter.cs 中如果投影模式下传入的是其他表达式如方法调用、复杂逻辑会抛出InvalidOperationExceptionConstructUsing for projection is support only New and MemberInit expression.带 destination 参数的重载当目标对象已存在例如映射到已有目标对象时ConstructUsing还有一个带destination参数的重载可以读取目标对象的当前状态参与构造//Example using an overload with destination parameter TypeAdapterConfigTSource, TDestination.NewConfig() .ConstructUsing((src, destination) new TDestination(src.Id, destination?.Name ?? src.Name));对应源码位于 TypeAdapterSetter.cs该重载只在UseDestinationValue或目标值存在时才有意义。仓库测试 WhenPerformingAfterMapping.cs 也展示了该重载与 AfterMapping 组合使用的场景。三、用 MapToConstructor 映射到构造函数默认情况下 Mapster 只映射字段和属性。通过MapToConstructor可以将映射目标改为构造函数参数让不可变 DTO只有只读属性、没有 setter也能被完整填充。全局默认开启在全局设置中开启所有类型对默认映射到构造函数//global level TypeAdapterConfig.GlobalSettings.Default.MapToConstructor(true);类型对级别开启也可以只针对某个类型对开启//type pair TypeAdapterConfigPoco, Dto.NewConfig().MapToConstructor(true);MapToConstructor(bool)的源码实现位于 TypeAdapterSetter.cs开启时在 Settings 中写入*标记关闭时写入nullpublic static TSetter MapToConstructorTSetter(this TSetter setter, bool value) where TSetter : TypeAdapterSetter { setter.CheckCompiled(); setter.Settings.MapToConstructor value ? * : null; return setter; }CheckCompiled()意味着一旦该配置对应的映射已经编译完成就不能再修改否则会抛异常——这也是 Mapster 所有设置项的统一行为。自定义构造函数参数映射Pascal case当构造函数参数名与源成员名不一致时需要自定义映射此时必须使用Pascal case帕斯卡命名即首字母大写class Poco { public string Id { get; set; } ... } class Dto { public Dto(string code, ...) { ... } }TypeAdapterConfigPoco, Dto.NewConfig() .MapToConstructor(true) .Map(Code, Id); //use Pascal caseMap(Code, Id)的含义是目标构造函数的Code参数Pascal case 形式从源对象的Id属性取值。构造函数参数在内部被规范化为 Pascal case 表示因此自定义映射必须遵守这一约定。多构造函数时如何自动选择如果目标类有 2 个或更多构造函数Mapster 会自动选择能够满足映射的、参数数量最多的那个构造函数class Poco { public int Foo { get; set; } public int Bar { get; set; } } class Dto { public Dto(int foo) { ... } public Dto(int foo, int bar) { ...} //-- Mapster will use this constructor public Dto(int foo, int bar, int baz) { ... } }在这个例子中Poco只有Foo、Bar两个可映射成员因此Dto(int foo, int bar)是能完全映射的参数最多的构造函数会被选中Dto(int foo, int bar, int baz)虽然参数更多但因为Poco没有Baz成员无法满足映射。显式指定 ConstructorInfo除了自动选择你还可以通过反射拿到ConstructorInfo并显式传入var ctor typeof(Dto).GetConstructor(new[] { typeof(int), typeof(int) }); TypeAdapterConfigPoco, Dto.NewConfig() .MapToConstructor(ctor);对应源码位于 TypeAdapterSetter.cs该方法包含两个重要的运行时校验构造函数声明类型必须能赋值给TDestination否则抛出ArgumentException(Constructor cannot be assigned to type TDestination)构造函数的声明类型不能是抽象类否则抛出ArgumentException(Constructor of abstract type cannot be created)。仓库测试 WhenMappingToConstructor.cs 验证了显式指定构造函数的效果Dto定义了三个构造函数显式指定Dto(string id)后映射结果中Id被正确赋值而Name为 null、Age为 0其余可写属性Prop仍通过普通属性映射填充。四、源码级原理剖析构造工厂在 Settings 中的存储无论是ConstructUsing的哪个重载最终都统一写入Settings.ConstructUsingFactory其类型为FuncCompileArgument, LambdaExpression定义在 TypeAdapterSettings.cs。编译时CompileArgument.cs 通过GetConstructUsing()惰性求值该工厂internal LambdaExpression? GetConstructUsing() { if (_fetchConstructUsing) return _constructUsing; _constructUsing Settings.ConstructUsingFactory?.Invoke(this); _fetchConstructUsing true; return _constructUsing; }_fetchConstructUsing标志保证了同一个编译参数实例中工厂只被调用一次避免重复求值影响性能。构造函数选择算法MapToConstructor(true)与自动选择构造函数的完整逻辑在 ClassAdapter.cs 的CreateInstantiationExpression中若目标类型有默认构造函数、或已配置ConstructUsing且未配置MapToConstructor则走基类的默认实例化路径否则从Settings.MapToConstructor中读取ConstructorInfo若没有显式指定则通过destType.GetConstructors()获取所有构造函数按参数数量降序排序OrderByDescending(it it.GetParameters().Length)逐个尝试CreateClassConverter生成映射返回第一个能成功完成参数映射的构造函数FirstOrDefault(it it ! null)如果全部尝试失败则回退到第一个构造函数的非严格模式GetConstructorModel(constructors[0], false)若仍无法生成则回退到默认的实例化表达式。值得注意的是代码中destType还处理了目标为接口的情况通过DynamicTypeGenerator.GetTypeForInterface为接口动态生成实现类型再在其上寻找构造函数见 ClassAdapter.cs。无默认构造函数时的错误提示在 BaseAdapter.cs 中当最终无法创建目标实例且目标类型没有默认构造函数时会抛出带有明确指引的异常信息提示开发者改用ConstructUsing或MapWith。这条错误信息实际上就是何时应该使用本文配置项的最直接判断标准。五、典型实战场景映射到接口类型当目标是接口时ConstructUsing可以配合动态生成的接口实现类型使用。仓库测试 WhenUsingNonDefaultConstructor.cs 展示了将SimplePoco映射到ISimpleDtoWithDefaultConstructor接口时通过ConstructUsing提供具体实现类实例的做法TypeAdapterConfigSimplePoco, ISimpleDtoWithDefaultConstructor.NewConfig() .IgnoreNullValues(true) .ConstructUsing(src new SimpleDtoWithDefaultConstructor { Unmapped unmapped }) .Compile(); var dto TypeAdapter.AdaptISimpleDtoWithDefaultConstructor(simplePoco);搭配 AfterMapping 使用 destination 重载带destination参数的ConstructUsing重载适合在目标对象已存在的合并场景中使用它允许构造逻辑参考目标对象的当前值如destination?.Name ?? src.Name这样的回退策略。这种先构造、再 AfterMapping 收尾的组合在 WhenPerformingAfterMapping.cs 中均有测试覆盖。六、相关文档与测试原文档Constructor mapping设置项总览Settings 目录相关主题还包括 Setting values、Constructor 相关核心实现TypeAdapterSetter.csConstructUsing、MapToConstructor各重载定义ClassAdapter.cs构造函数自动选择算法BaseAdapter.cs无默认构造函数的异常提示TypeAdapterSettings.csConstructUsingFactory与MapToConstructor设置存储测试用例WhenMappingToConstructor.cs自动选择与显式ConstructorInfo两种模式WhenUsingNonDefaultConstructor.cs非默认构造函数、工厂方法、接口目标三种场景WhenPerformingAfterMapping.csConstructUsing与AfterMapping组合核心要点回顾ConstructUsing用于完全接管目标对象的创建自定义构造函数、工厂方法或初始化器MapToConstructor用于让映射结果直接注入构造函数参数当存在多个构造函数时 Mapster 自动选择参数最多且能完全映射的那个也可以显式传入ConstructorInfo精确控制自定义构造参数映射必须使用 Pascal case。两者都能与全局Default设置、投影Projection、接口目标等场景无缝配合。【免费下载链接】MapsterA fast, fun and stimulating object to object Mapper项目地址: https://gitcode.com/GitHub_Trending/ma/Mapster创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Hermes Agent 跑 ima 全自动入库,Base URL 填 TaoToken 的 API

Hermes Agent 跑 ima 全自动入库,Base URL 填 TaoToken 的 API

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 22:37:45 阅读更多 →
Cline 还要去 DeepSeek 官方申请 token?TaoToken 这样改接口地址

Cline 还要去 DeepSeek 官方申请 token?TaoToken 这样改接口地址

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 22:37:45 阅读更多 →
文件头必填项校验:DeepSeek Harness 用 TaoToken 决定 Obsidian 召回

文件头必填项校验:DeepSeek Harness 用 TaoToken 决定 Obsidian 召回

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 22:37:45 阅读更多 →

最新新闻

Unity Addressables构建全解析:原理、实操与优化指南

Unity Addressables构建全解析:原理、实操与优化指南

做Unity项目做久了,资源这块迟早会撞上Addressables。不少朋友在群里问,说照着官方文档看完前面几章,加载、卸载、依赖管理都跑通了,结果卡在最后一步构建上,出包量大、加载卡顿、ab包文件对不上,甚至构建一…

2026/9/18 23:18:06 阅读更多 →
oh-my-hermes:统一 Hermes 配置管理,让 React Native 性能优化更简单

oh-my-hermes:统一 Hermes 配置管理,让 React Native 性能优化更简单

1. 项目缘起:为什么我会折腾一套 Hermes 配置管理方案先交代一下背景。我一直在做 React Native 相关的性能优化工作,接触 Hermes 引擎其实比大多数人要早。Hermes 是 Facebook 专门为 React Native 打造的那套 JavaScript 引擎,它在 Android…

2026/9/18 23:18:06 阅读更多 →
FastStream 文档贡献指南:从本地构建到可测试代码示例的完整流程

FastStream 文档贡献指南:从本地构建到可测试代码示例的完整流程

FastStream 文档贡献指南:从本地构建到可测试代码示例的完整流程 【免费下载链接】faststream Asynchronous Python framework for event-driven services. A thin client for Kafka, RabbitMQ, NATS, Redis and MQTT with full access to native broker features, …

2026/9/18 23:18:06 阅读更多 →
UE高级运动系统实战:数据流、动画融合与性能优化

UE高级运动系统实战:数据流、动画融合与性能优化

1. 先把"高级运动系统"的边界划清楚1.1 高级运动系统究竟在解决什么问题刚接触 UE高级运动系统 的人,十有八九是被那种"转身会甩腿、跑动会压身、上下坡脚步能贴地"的角色手感吸引过来的。但真把工程拖进编辑器跑起来,往往第一反应是…

2026/9/18 23:18:06 阅读更多 →
CANN Runtime 模型运行时实例(Model RI)任务更新实战:基于 aclmdlRICaptureTaskGrp 与 aclmdlRICaptureTaskUpdate 的算子级模型更新

CANN Runtime 模型运行时实例(Model RI)任务更新实战:基于 aclmdlRICaptureTaskGrp 与 aclmdlRICaptureTaskUpdate 的算子级模型更新

CANN Runtime 模型运行时实例(Model RI)任务更新实战:基于 aclmdlRICaptureTaskGrp 与 aclmdlRICaptureTaskUpdate 的算子级模型更新 【免费下载链接】runtime 本项目提供CANN运行时组件和维测功能组件。 项目地址: https://gitcode.com/ca…

2026/9/18 23:18:06 阅读更多 →
Cursor 用 Ctrl+K 写冒泡排序,Base URL 填 TaoToken

Cursor 用 Ctrl+K 写冒泡排序,Base URL 填 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 23:17:06 阅读更多 →

日新闻

Matlab手写逻辑回归:从数学原理到多变量概率预测模型实现

Matlab手写逻辑回归:从数学原理到多变量概率预测模型实现

很多朋友第一次看到"逻辑回归"这四个字,第一反应就是——这玩意儿是个回归模型吧?我当年也是在Matlab里跑完一段代码,看着输出的0.73、0.86这种概率值,才回过神来:这家伙其实是披着回归外衣的分类神器&#…

2026/9/18 0:00:28 阅读更多 →
高值医用耗材研报PDF:用Python完成字段抽取、清洗与趋势预测

高值医用耗材研报PDF:用Python完成字段抽取、清洗与趋势预测

简介:这份报告是2023-2028年高值医用耗材行业调研及发展前景趋势预测报告,面向医疗器械企业管理者、投资机构、行业研究人员及关注政策变化的从业者,用于把握行业监管动向、市场格局与未来趋势。报告以PDF格式呈现,共1个文件、整体…

2026/9/18 0:00:28 阅读更多 →
三维高斯场赋能世界模型:几何语义蒸馏与机器人决策实战

三维高斯场赋能世界模型:几何语义蒸馏与机器人决策实战

先把我自己的背景交代一下:我之前在搞具身智能和机器人导航相关的项目,很长一段时间里都被“环境表示”这件事卡着。传统做法是用点云或者网格做几何建模,语义信息另外再跑分割模型,两套东西各管各的,时间一长就会发现…

2026/9/18 0:00:28 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/16 19:03:19 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/17 7:57:36 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/17 10:19:14 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →