如何用AutoMapper将Colli列表映射为数量扩容的ColliDto列表?
问题:AutoMapper实现按Count生成对应数量的Dto列表
现有类定义
public class Colli { public int Count { get; set; } public string Description { get; set; } } public class Shipment { public List<Colli> Collis { get; set; } } public class ShipmentDto { public List<ColliDto> Collis { get; set; } } public class ColliDto { public string Description { get; set; } }
需求说明
根据每个Colli的Count值,生成对应数量、描述相同的ColliDto列表。
示例输入:
{ "collis": [ { "count": 2, "description": "Colli 1" }, { "count": 1, "description": "Colli 2" } ] }
示例输出:
{ "collis": [ { "description": "Colli 1" }, { "description": "Colli 1" }, { "description": "Colli 2" } ] }
尝试的实现及问题
编写了如下ITypeConverter转换器,期望将单个Colli转为对应数量的List<ColliDto>:
public class ColliConverter : ITypeConverter<Colli, List<ColliDto>> { public List<ColliDto> Convert(Colli source, List<ColliDto> destination, ResolutionContext context) { var retval = new List<ColliDto>(); for (int i = 0; i < source.Count; i++) { retval.Add(context.Mapper.Map<ColliDto>(source)); } return retval; } }
并配置映射:
CreateMap<Colli, List<ColliDto>>().ConvertUsing<ColliConverter>();
但调试发现转换器未被调用。
解决方案
这个需求完全可以通过AutoMapper实现,无需手动全量映射。之前的转换器未生效的原因是:AutoMapper处理List<Colli>到List<ColliDto>时,默认会逐个将Colli映射为ColliDto,而非调用单个Colli到List<ColliDto>的转换器。正确的做法是针对Shipment到ShipmentDto的Collis字段配置转换逻辑。
方式一:自定义值解析器(ValueResolver)
定义一个值解析器来处理Collis字段的展开逻辑:
public class CollisResolver : IValueResolver<Shipment, ShipmentDto, List<ColliDto>> { private readonly IMapper _mapper; public CollisResolver(IMapper mapper) { _mapper = mapper; } public List<ColliDto> Resolve(Shipment source, ShipmentDto destination, List<ColliDto> destMember, ResolutionContext context) { var result = new List<ColliDto>(); foreach (var colli in source.Collis) { for (int i = 0; i < colli.Count; i++) { result.Add(_mapper.Map<ColliDto>(colli)); } } return result; } }
然后配置映射关系:
// 先配置Colli到ColliDto的基础字段映射(如果有更多字段,AutoMapper会自动匹配同名字段) CreateMap<Colli, ColliDto>(); // 配置Shipment到ShipmentDto的映射,指定Collis字段使用自定义解析器 CreateMap<Shipment, ShipmentDto>() .ForMember(dest => dest.Collis, opt => opt.MapFrom<CollisResolver>());
方式二:直接在映射配置中使用自定义逻辑
如果不需要单独的解析器类,也可以直接在映射配置中写逻辑:
CreateMap<Colli, ColliDto>(); CreateMap<Shipment, ShipmentDto>() .ForMember(dest => dest.Collis, opt => opt.MapFrom(src => src.Collis.SelectMany(colli => Enumerable.Repeat(_mapper.Map<ColliDto>(colli), colli.Count) ).ToList() ));
以上两种方式都能实现需求,无需手动编写全量映射代码。
内容的提问来源于stack exchange,提问作者Frederik
相关产品推荐
相关产品推荐

