如何使用AutoMapper映射多列表到同一集合且不覆盖原有值
解决方案
核心问题说明
你遇到的两个问题原因很明确:
- 重复对
Animals属性配置MapFrom时,AutoMapper默认采用赋值逻辑,后配置的Pig映射会直接覆盖之前的Cow映射结果 - 直接调用
Concat报错是因为List<Cow>和List<Pig>是完全不同的泛型类型,C#语法不允许直接合并两种无继承关系的泛型集合
方案1:显式配置合并(推荐,可控性高)
直接在MapFrom中使用ResolutionContext获取当前Mapper实例,依次映射每个集合并合并即可,后续新增类型只要加一行AddRange代码即可,非常适合你10种类型的场景:
public class MappingResourceZoo : Profile { public MappingResourceZoo() { CreateMap<MammalHouse, Zoo>() .ForMember(dest => dest.Animals, opt => opt.MapFrom((src, dest, member, ctx) => { var animals = new List<Animal>(); // 依次添加所有需要合并的集合,新增类型只要加对应行即可 animals.AddRange(ctx.Mapper.Map<IEnumerable<Animal>>(src.Cows)); animals.AddRange(ctx.Mapper.Map<IEnumerable<Animal>>(src.Pigs)); // animals.AddRange(ctx.Mapper.Map<IEnumerable<Animal>>(src.Dogs)); // animals.AddRange(ctx.Mapper.Map<IEnumerable<Animal>>(src.Sheep)); return animals; })); CreateMap<Cow, Animal>() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species)); CreateMap<Pig, Animal>() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Species)); } }
这个方案不需要修改任何第三方模型,也不需要额外的自定义类,你现有测试代码可以直接跑通,返回的Animals集合会包含4个元素。
方案2:自动反射遍历(适合后续频繁新增类型的场景)
如果你后续还会不断新增动物类型,可以用反射自动遍历MammalHouse中所有集合属性,自动映射合并,后续新增类型只要配置对应单个对象到Animal的映射即可,不需要修改MammalHouse到Zoo的映射代码:
CreateMap<MammalHouse, Zoo>() .ForMember(dest => dest.Animals, opt => opt.MapFrom((src, dest, member, ctx) => { var animals = new List<Animal>(); // 自动获取所有List类型的属性 var listProperties = src.GetType().GetProperties() .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(List<>)); foreach (var prop in listProperties) { var value = prop.GetValue(src) as System.Collections.IEnumerable; if (value == null) continue; // 自动映射为Animal集合 var mapped = ctx.Mapper.Map<IEnumerable<Animal>>(value); animals.AddRange(mapped); } return animals; }));
内容的提问来源于stack exchange,提问作者Linda Lawton - DaImTo
相关产品推荐
相关产品推荐

