AutoMapper从7版本升级到10版本后的对象映射问题解决
问题描述
以下是在LinqPad 5(.Net Framework)中编写的代码示例:
void Main() { var o = new A() { b = new B() { Msj = "Hello, world!" } }; var r = MapObject<C, A>(o); r.Dump(); } public class A { public B b {get;set;} } public class B { public string Msj {get;set;} } public class C { public D b { get; set; } } public class D { public string Msj { get; set; } } private static Tdst MapObject<Tdst, Tori>(Tori obj) { var configMapper = new AutoMapper.MapperConfiguration(cfg => cfg.CreateMap<Tori, Tdst>()); var mapper = configMapper.CreateMapper(); return mapper.Map<Tdst>(obj); }
这段代码在AutoMapper 7版本中运行正常,但升级到10版本后,抛出如下错误:
AutoMapperMappingException: Error mapping types. Mapping types: A -> C UserQuery+A -> UserQuery+C Type Map configuration: A -> C UserQuery+A -> UserQuery+C Destination Member: b
已知类A和C结构完全一致,但来自不同Web服务(不同命名空间),需要修改MapObject方法,使其在AutoMapper 10中正常工作。
注:已通过Mapster解决该问题,好奇AutoMapper的解决方案。
解决方案
AutoMapper从8.x版本开始,默认不再自动映射嵌套类型,必须显式配置嵌套类型的映射规则。以下是两种修改方案:
方案1:针对单个嵌套属性配置
如果只需要处理示例中的b属性,可直接显式添加嵌套类型的映射:
private static Tdst MapObject<Tdst, Tori>(Tori obj) { var configMapper = new AutoMapper.MapperConfiguration(cfg => { cfg.CreateMap<Tori, Tdst>(); // 显式添加嵌套类型B到D的映射 cfg.CreateMap<B, D>(); }); var mapper = configMapper.CreateMapper(); return mapper.Map<Tdst>(obj); }
方案2:通用嵌套类型自动配置
如果需要支持任意同名同结构的嵌套属性,可通过反射自动遍历并添加映射规则:
private static Tdst MapObject<Tdst, Tori>(Tori obj) { var configMapper = new AutoMapper.MapperConfiguration(cfg => { cfg.CreateMap<Tori, Tdst>(); // 遍历源类型和目标类型的所有属性 var sourceProps = typeof(Tori).GetProperties(); var destProps = typeof(Tdst).GetProperties(); foreach (var srcProp in sourceProps) { var destProp = destProps.FirstOrDefault(p => p.Name == srcProp.Name); // 仅处理引用类型(排除值类型和字符串)的同名属性 if (destProp != null && !srcProp.PropertyType.IsValueType && srcProp.PropertyType != typeof(string)) { cfg.CreateMap(srcProp.PropertyType, destProp.PropertyType); } } }); var mapper = configMapper.CreateMapper(); return mapper.Map<Tdst>(obj); }
原因说明
AutoMapper 7及更早版本会自动尝试映射同名的嵌套类型,即使它们属于不同命名空间。但从8.x版本开始,为了提升性能、减少意外映射的风险,官方默认关闭了这一自动行为,要求开发者显式声明所有需要映射的类型对。
内容的提问来源于stack exchange,提问作者rasputino
相关产品推荐
相关产品推荐

