如何编写ForAllMaps函数:实现条件映射且避免异常、不影响其他映射
解决AutoMapper中条件映射避免异常的问题
我明白你遇到的困扰了——直接调用ForMember会在目标类型没有对应属性时抛出异常,还得保证不影响其他已有的映射配置。核心思路就是先判断条件是否满足,再执行映射配置,而不是不管三七二十一就调用ForMember。
解决方案代码
下面这段代码完美匹配你的需求:先检查源类型是否有Id属性,再检查目标类型是否存在[源类型名称]Id属性,只有两个条件都满足时才配置映射:
ForAllMaps((typeMap, mappingExpression) => { // 检查源类型是否包含公共实例的Id属性 var sourceIdProp = typeMap.SourceType.GetProperty("Id", BindingFlags.Public | BindingFlags.Instance); if (sourceIdProp == null) { return; // 源没有Id属性,直接跳过 } // 构建目标属性名:源类型名称 + "Id"(比如Company → CompanyId) var targetPropName = $"{typeMap.SourceType.Name}Id"; // 检查目标类型是否包含对应的公共实例属性 var targetProp = typeMap.DestinationType.GetProperty(targetPropName, BindingFlags.Public | BindingFlags.Instance); if (targetProp != null) { // 两个条件都满足,配置映射 mappingExpression.ForMember(targetPropName, opt => opt.MapFrom(sourceIdProp.Name)); } });
关键细节说明
- 避免异常的核心:通过反射提前检查目标属性是否存在,只有存在时才调用
ForMember,从根源上避免了属性不存在导致的异常。 - 不干扰其他映射:AutoMapper的规则优先级是手动配置 > 全局ForAllMaps配置,所以如果某个属性已经有手动或自动的映射规则,你的全局条件配置不会覆盖它,只会在没有规则且满足条件时添加新规则。
- 可选优化:如果需要支持大小写不敏感的属性匹配(比如目标属性是
companyId而不是CompanyId),可以修改GetProperty的调用,加上忽略大小写的参数:var targetProp = typeMap.DestinationType.GetProperty(targetPropName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
这样既实现了你想要的条件映射逻辑,又保证了整个映射配置的稳定性,不会因为属性不存在而崩溃,也不会影响其他已有的映射规则。
内容的提问来源于stack exchange,提问作者AuthorProxy
相关产品推荐
相关产品推荐

