首页/新闻资讯/正文详情

AutoMapper 12.0 升级指南:等效配置覆盖规则、ResolutionContext 重构与命名约定性能优化

发布时间:2026/9/24 17:07:51 来源:云帆数科 栏目:资讯中心
AutoMapper 12.0 升级指南:等效配置覆盖规则、ResolutionContext 重构与命名约定性能优化
后端【免费下载链接】AutoMapperA convention-based object-object mapper in .NET.项目地址https://gitcode.com/gh_mirrors/au/AutoMapper点击查看免费下载导读本文以 12.0-Upgrade-Guide.md 为主线系统梳理从 12.0 版本开始 AutoMapper 引入的三类破坏性变更同图/同成员的等效配置互相覆盖规则、ResolutionContext.Options的移除与替代方案以及为性能而简化的命名约定实现。文中将结合当前仓库源码如 ResolutionContext.cs、Conventions.cs与单元测试如 ContextItems.cs、ForAllMaps.cs逐项还原变更的底层原理与迁移写法帮助你快速定位受影响的配置代码并完成升级。一、等效设置互相覆盖Equivalent settings overwrite each other12.0 明确了配置的“后写覆盖先写”语义同一张映射per map和同一个成员per member上的等效设置只能保留一份后配置的会覆盖先配置的。这条规则同时作用于 Map 运行时映射与 ProjectTo 投影查询理解它能避免升级后出现“配置莫名失效”的困惑。1.1 规则粒度每张映射一个类型转换器每个成员一个解析器每张 map 只能有一个类型转换器type converterConvertUsing/ConvertUsingITypeConverter这类针对整个 Source→Destination 类型的转换配置同一张 map 内重复设置时后者覆盖前者。每个 member 只能有一个解析器resolverMapFrom、MapFromTValueResolver、ResolveUsing等针对单个成员的取值配置后设置者覆盖先设置者。1.2 关键陷阱等价配置并不总是显而易见官方指南特别强调很多配置表面上不同、实质上是“等价”的例如值转换器value converter本质上是解析器resolver的一种特化因此同一成员上后写的ConvertUsing会覆盖先写的MapFrom。也就是说下面这段代码最终生效的是ConvertUsingvar config new MapperConfiguration(cfg { cfg.CreateMapSource, Dest() .ForMember(d d.Value, opt opt.MapFrom(src src.OtherValue)) // 先写被覆盖 .ForMember(d d.Value, opt opt.ConvertUsing(new SomeConverter())); // 后写生效 });同理同一成员上先写MapFromTResolver再写MapFrom(expr)后者也会生效。由于覆盖顺序就是代码书写顺序迁移时可优先检查链式配置中同一成员的多次.ForMember调用。1.3 不能为Map和ProjectTo分别配置12.0 起同一张 map / 同一个成员上不能分别为对象映射Map和投影查询ProjectTo保存两套独立配置。映射配置在 AutoMapper 中是共享的一张TypeMap/ 一个PropertyMap同时驱动运行时表达式与查询投影见 ProjectionBuilder.cs。如果你之前通过不同分支为Map与ProjectTo设置了不同行为升级后必须合并为同一套配置或改用条件表达式在单一配置内区分场景。1.4ForAllMaps/ForAllPropertyMaps的覆盖场景ForAllMaps所有 map 生效与ForAllPropertyMaps满足条件的成员生效是批量配置入口。由于它们在实际创建 map 时执行可能覆盖某张具体 map 里已经单独设置的内容。这是文档明确提示的“另一种可能发生覆盖的场景”。参考 ForAllMaps.cs 中的测试对多张 map 统一调用ForMember(Number, o o.MapFromMinusOneResolver())最终三张 map 的Number全部被批量解析器接管var config new MapperConfiguration(cfg { cfg.CreateMapSource, Destination(); cfg.CreateMapSource1, Destination1(); cfg.CreateMapSource2, Destination2(); cfg.ForAllMaps((tm, map) map.ForMember(Number, o o.MapFromMinusOneResolver())); }); // 三张 map 的 Number 均被映射为 -1批量配置同样适用于构造参数与值转换器。例如 ValueConverters.cs 中通过ForAllPropertyMaps对“源类型为int、目标类型为string”的所有成员统一应用值转换器cfg.ForAllPropertyMaps( pm pm.SourceType typeof(int) pm.DestinationType typeof(string), (pm, opt) opt.ConvertUsing(new EightDigitIntToStringConverter()));因此升级时若发现“某个成员的单独配置没生效”应从三个方面排查同成员链式配置的后写覆盖、Map/ProjectTo共享配置冲突、以及ForAllMaps/ForAllPropertyMaps批量覆盖。相关 API 的定义可查阅 Profile.cs 与 AutoMapperSpecBase.cs。二、ResolutionContext.Options已移除2.1 变更内容12.0 移除了ResolutionContext.Options属性以及通过它暴露的ServiceCtor等访问方式。过去在自定义 resolver / type converter / value converter 中通过context.Options读取映射参数与构造服务的代码升级后需要改写。从 ResolutionContext.cs 可以看到 12.x 当前的公开上下文形态ResolutionContext.Items返回Dictionarystring, object即Map调用时通过 options 传入的上下文项ResolutionContext.TryGetItems(out items)12.0.1 新增用于安全探测是否传入了上下文未传入时返回false而不是抛异常ResolutionContext.State在Map调用中传入的单个状态对象与Items在同一Map调用中互斥详见 IMappingOperationOptions.cs 中两个属性的注释ResolutionContext.Mapper用于在自定义逻辑中继续发起嵌套映射。2.2 使用Items传递上下文数据在Map调用侧传入上下文项var dest mapper.MapSource, Dest(source, opt { opt.Items[Item] 10; });在 resolver / converter 侧读取参考 ContextItems.cs 的When_mapping_with_contextual_values测试public class ContextResolver : IMemberValueResolverSource, Dest, int, int { public int Resolve(Source src, Dest d, int source, int dest, ResolutionContext context) source (int)context.Items[Item]; }需要注意的是Items的取值逻辑要求Map调用必须使用带ActionIMappingOperationOptions的重载。如果用了不带 options 的重载直接访问context.Items会抛出InvalidOperationException异常信息原文为见 ResolutionContext.csContext.Items are only available when using a Map overload that takes ActionIMappingOperationOptions! Consider using Context.TryGetItems instead.对应的负向测试When_mapping_with_contextual_values_wrong_overloadContextItems.cs验证了这一行为。2.3 用TryGetItems探测上下文12.0.1当同一个 resolver / converter 既要兼容“不传上下文”的Map调用、又要支持传入覆盖值时使用TryGetItems最稳妥public override ExpressionFuncint, int ProjectToExpression() throw new NotSupportedException(); // 类型转换器内部 c c.TryGetItems(out var items) ? (int)items[override] : s测试用例 Context_try_get_items 验证了两种调用均不抛异常Mapint(42).ShouldBe(42); // 未传上下文取源值 Mapper.Mapint(42, o o.Items[override] 43).ShouldBe(43); // 传入上下文取覆盖值2.4State单值状态的替代方案如果你只需要传入一个对象而不是键值集合可以用State。它与Items在同一Map调用中互斥测试 When_mapping_with_context_state 展示了完整用法var dest config.CreateMapper().MapSource, Dest( new Source { Value 5 }, opt { opt.State 10; }); // State 传入单个对象 // resolver 中读取 public int Resolve(Source src, Dest d, int source, int dest, ResolutionContext context) source (int)context.State;从实现上看IMappingOperationOptions.csMappingOperationOptions.Items实际上是惰性把State初始化为字典后复用同一存储这也解释了二者“互斥”的语义一次Map调用只能以一种形式携带上下文。2.5ServiceCtor改用依赖注入或在Map调用中传入文档明确建议放弃通过ResolutionContext访问ServiceCtor的做法改用依赖注入或在Map调用中显式传入所需对象。当前实现中 ResolutionContext.cs 的ServiceCtor()仅保留为内部兜底_options?.ServiceCtor ?? _mapper.ServiceCtor用于CreateInstance创建目标实例不再作为面向使用者的公共上下文 API。若个别场景仍需要在单次映射中注入服务可借助IMappingOperationOptions.ConstructServicesUsing子容器场景见 IMappingOperationOptions.csmapper.MapSource, Dest(source, opt opt.ConstructServicesUsing(type myChildContainer.Resolve(type)));更常规的做法是在MapperConfiguration构造时通过ConstructServicesUsing注册服务提供方或让 resolver / converter 直接使用项目自身的 DI 容器。相关实践可进一步参考 Dependency-injection.md。三、命名约定为性能而简化的实现3.1 变更动机12.0 出于性能考虑简化了命名约定的匹配实现尤其影响扁平化映射的名称拆分逻辑。官方立场是与其处理每一种命名怪癖不如提供一个简单快速、覆盖大多数场景的实现如果你的场景无法被默认实现覆盖可以编写自定义命名约定。3.2 源码中的实现分层从 Conventions.cs 可以看到命名匹配的当前结构MemberConfiguration保存SourceNamingConvention、DestinationNamingConvention以及NameToMemberMappers列表MemberConfiguration.Seal()Conventions.cs当源、目标命名约定都是默认的PascalCaseNamingConvention时走专门的DefaultNameSplitMember快速路径否则走通用的ConventionsNameSplitMember。这就是“简化 性能优化”的核心所在——默认情形下不再经过通用的约定拆分流程NameSplitMember抽象基类及其两个子类DefaultNameSplitMember直接按大写字母边界切分并递归匹配ConventionsNameSplitMember则先按DestinationNamingConvention.Split切分、再按SourceNamingConvention.SeparatorCharacter重组后逐段匹配反向映射时二者互换见 Conventions.cs。INamingConvention接口INamingConvention.cs只包含两个成员自定义成本很低public interface INamingConvention { string[] Split(string input); string SeparatorCharacter { get; } }仓库内置三种约定实现实现SeparatorCharacterSplit行为用途PascalCaseNamingConvention按大写字母边界拆分含缩写/连续大写处理默认约定支持InnerSourceValue这类扁平化名称LowerUnderscoreNamingConvention_按下划线拆分支持ja_se_zovem_imenom这类 snake_case 名称ExactMatchNamingConventionnull不拆分返回空数组仅精确匹配用于关闭扁平化拆分3.3 自定义命名约定的写法在全局配置中覆盖MapperConfigurationExpression/Profile均暴露SourceMemberNamingConvention与DestinationMemberNamingConvention见 IProfileExpression.cs 与 Profile.cspublic sealed class KebabCaseNamingConvention : INamingConvention { public string SeparatorCharacter -; public string[] Split(string input) input.Split(-, StringSplitOptions.RemoveEmptyEntries); } var config new MapperConfiguration(cfg { cfg.SourceMemberNamingConvention new KebabCaseNamingConvention(); cfg.DestinationMemberNamingConvention new KebabCaseNamingConvention(); });如果需要彻底关闭名称拆分只做精确匹配把两侧约定都设为ExactMatchNamingConvention.Instance即可。测试 NamingConventions.cs 验证了关闭后DestinationMemberNamingConvention ExactMatchNamingConvention.Instance时COMPANY_Name这类名称将不再被自动匹配而进入未映射校验错误。反向映射Reverse Map同样遵循命名约定测试When_mapping_with_lowercase_naming_conventions_two_waysNamingConventions.cs演示了 snake_case ↔ PascalCase 双向往返映射——正向用SourceMemberNamingConvention LowerUnderscoreNamingConvention反向用DestinationMemberNamingConvention LowerUnderscoreNamingConvention。此外若你的命名差异属于前缀/后缀/字符串替换类如RecognizePrefixes、RecognizePostfixes、ReplaceMemberName这些能力仍由PrePostfixName与ReplaceName两个ISourceToDestinationNameMapper承担见 Conventions.cs与 12.0 的命名约定简化互不冲突。相关完整说明可参考 Configuration.md。四、升级迁移清单结合上文升级到 AutoMapper 12.x 时建议按以下顺序自查检查等效配置覆盖搜索同一 map 中重复的ConvertUsing/MapFrom/ResolveUsing链式调用确认最终生效项符合预期确认没有为Map与ProjectTo分别维护两套配置留意ForAllMaps/ForAllPropertyMaps对单张 map 配置的批量覆盖。替换ResolutionContext.Options将读取上下文项的代码改为context.Items若需要兼容“未传上下文”的调用使用 12.0.1 起的context.TryGetItems需要传单个对象时改用State与Items互斥。移除ServiceCtor依赖改用依赖注入或在Map调用中通过ConstructServicesUsing/Items/State显式传入所需对象。验证命名约定行为运行AssertConfigurationIsValid校验未映射成员若默认的 PascalCase 快速路径无法满足命名习惯按INamingConvention编写自定义约定全局或按 Profile 设置或直接使用ExactMatchNamingConvention.Instance关闭拆分。五、延伸阅读Custom-type-converters.md每张 map 的类型转换器配置Custom-value-resolvers.md每成员解析器与MapFromTResolver用法Value-converters.md值转换器与解析器之间的关系Reverse-Mapping-and-Unflattening.md反向映射中的命名约定与ForPathQueryable-Extensions.mdProjectTo与 Map 共享配置的说明Dependency-injection.mdConstructServicesUsing与 DI 集成13.0-Upgrade-Guide.md12.x 之后的后续版本升级指引赞分享后端【免费下载链接】AutoMapperA convention-based object-object mapper in .NET.项目地址https://gitcode.com/gh_mirrors/au/AutoMapper点击查看免费下载相关推荐Rome 命名规范 Lint 规则 useNamingConvention 完整指南覆盖全代码库的命名约定检查与自动修复Rome 命名规范 Lint 规则 useNamingConvention 完整指南覆盖全代码库的命名约定检查与自动修复 本文全面解读 Rome该项目仓库开发工具CLILint格式化静态分析代码质量构建工具Apollo配置优先级多层配置覆盖规则详解Apollo配置优先级多层配置覆盖规则详解 在分布式系统中配置管理的复杂性往往来源于多环境、多集群、多应用间的配置协同。Apollo配置中心Apollo配置中心后端微服务PARD-Qwen3-0.6B核心原理深度解析并行草稿模型适配技术揭秘PARD Qwen3 0.6B核心原理深度解析并行草稿模型适配技术揭秘 想要了解如何通过并行草稿模型技术将大语言模型推理速度提升3倍以上吗PARD Qwen上一篇如何免费将网易云 NCM 文件转换为 MP3ncmdump 新手完整指南下一篇QQ空间备份怎么免费做说说、相册、日志一次导出的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Nginx UI Logrotate 配置指南:从参数解读到 crontab 调度原理
Nginx UI Logrotate 配置指南:从参数解读到 crontab 调度原理

后端前端运维MCP 服务 【免费下载链接】nginx-ui Yet another WebUI for Nginx 项目地址: https://gitcode.com/gh_mirrors/ngi/nginx-ui 点击查看 免费下载 导读 本指南围绕 Nginx UI 的 logrotate 配置模块展开,系统讲解 Enabled、CMD、Interval 三个… · 2026/9/24 17:07:44

PaddleSpeech FastSpeech2 GTA Mel 生成指南:基于 gen_gta_mel.py 为声码器微调准备训练数据
PaddleSpeech FastSpeech2 GTA Mel 生成指南:基于 gen_gta_mel.py 为声码器微调准备训练数据

人工智能语音音频NLP媒体生成 【免费下载链接】PaddleSpeech Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation … · 2026/9/24 17:07:44

【Socket 进阶之路】第 11 章 网络压测、Wireshark 抓包实战、性能瓶颈定位与调优,网络开发全流程闭环
【Socket 进阶之路】第 11 章 网络压测、Wireshark 抓包实战、性能瓶颈定位与调优,网络开发全流程闭环

💖 点赞 收藏 关注,Socket 工业级网络编程全套实战持续更新!✨ 本专栏 全程手写源码、无阉割、纯工程0. 前言到上一章为止,我们已经掌握了 Socket 基础、IO 多路复用(select/poll/epoll)、事件驱动开源库… · 2026/9/24 17:07:44

linux中文编程之一入门008
linux中文编程之一入门008

· 2026/9/24 17:48:04

16:Python语法-字符串str
16:Python语法-字符串str

一、字符串1、一个字符串可以存放任意数量的字符。如:"hello" cwc """vwerv"""。2、字符串是有序的,每个字符都有其对应的下标,与列表一致。3、字符串不可变、有序、可遍历。二、字符串切片与列表切… · 2026/9/24 17:47:58

Agent 消息与事件工程笔记
Agent 消息与事件工程笔记

摘要:LLM 无状态,状态要在端点攒起来、过程要流出去——攒起来的是 Message,流出去的是 Event,这是 agent loop 上两个最基本的数据面。本文把它们拆开讲:各是什么、一轮 loop 里怎么流动、四家框架怎么实现、跨边界怎么靠 MCP / A2A / AG-UI 统一,最后落到工程上怎么用、… · 2026/9/24 17:47:58

内耗分类的术语大全的庖丁解牛
内耗分类的术语大全的庖丁解牛

总纲:内耗分类,是对精神自我消耗的归类体系。内耗本质是心理资源被无产出的思虑、冲突、反复拉扯持续占用,没有对外行动产出,心力却不断损耗。分类的意义,是识别内耗的源头,区分是思维、情绪、关系还是信念… · 2026/9/24 17:47:58

自卑分类的术语大全的庖丁解牛
自卑分类的术语大全的庖丁解牛

总纲:自卑,是自我价值感偏低的心理状态,核心是内在对自己持续低估,觉得自身不足、不配、不如他人。自卑不是单一情绪,是一套复合感受体系。分类的目的,区分自卑的来源、触发场景与表现形式,分清… · 2026/9/24 17:47:58

回调机制详解:从概念到 Spring 实践
回调机制详解:从概念到 Spring 实践

回调机制详解:从概念到 Spring 实践 一、什么是回调? 回调(Callback)是一种编程模式:把一段代码(函数或对象)作为参数传给另一个方法,由那个方法在合适的时机反过来调用这段代码。 通… · 2026/9/24 17:47:58

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码