如何让AutoMapper与继承List的自定义PagedList兼容?
问题描述
已配置如下AutoMapper映射:
CreateMap<Stuff, StuffDto>();
以下映射可正常工作:
StuffDto stuffDto = _mapper.Map<Stuff, StuffDto>(stuff);
以下映射也可正常工作:
List<StuffDto> stuffDtoList = _mapper.Map<List<Stuff>, List<StuffDto>>(stuffList);
但以下映射无法正常运行:
PagedList<StuffDto> stuffDtoList = _mapper.Map<PagedList<Stuff>, PagedList<StuffDto>>(pagedStuff);
错误信息:
needs to have a constructor with 0 args or only optional args. Validate your configuration for details.
PagedList<T>类定义如下:
public class PagedList<T> : List<T> { public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize) { CurrentPage = pageNumber; TotalPages = (int)Math.Ceiling(count / (double)pageSize); PageSize = pageSize; TotalCount = count; AddRange(items); } public int CurrentPage { get; set; } public int TotalPages { get; set; } public int PageSize { get; set; } public int TotalCount { get; set; } public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize) { var count = await source.CountAsync(); var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync(); return new PagedList<T>(items, count, pageNumber, pageSize); } }
请问如何让_mapper.Map<PagedList<Stuff>, PagedList<StuffDto>>(pagedStuff);像List一样正常工作?
解决方案
方案1:为PagedList添加无参构造函数
给PagedList<T>添加无参构造,让AutoMapper可以先创建实例再赋值属性和集合元素:
public class PagedList<T> : List<T> { // 添加无参构造 public PagedList() { } public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize) { CurrentPage = pageNumber; TotalPages = (int)Math.Ceiling(count / (double)pageSize); PageSize = pageSize; TotalCount = count; AddRange(items); } // 其他属性和方法保持不变 }
补充泛型PagedList的映射配置:
CreateMap(typeof(PagedList<>), typeof(PagedList<>));
方案2:配置AutoMapper使用带参构造函数
如果不想添加无参构造,直接告诉AutoMapper用原PagedList的参数构造目标对象:
单个实体对配置
CreateMap<PagedList<Stuff>, PagedList<StuffDto>>() .ConstructUsing(src => new PagedList<StuffDto>( _mapper.Map<List<Stuff>, List<StuffDto>>(src), src.TotalCount, src.CurrentPage, src.PageSize ));
泛型通用配置(适配所有PagedList转换)
CreateMap(typeof(PagedList<>), typeof(PagedList<>)) .ConstructUsing((src, ctx) => { var sourceItemType = src.GetType().GetGenericArguments()[0]; var destItemType = ctx.DestinationType.GetGenericArguments()[0]; // 映射集合元素 var mappedItems = ctx.Mapper.Map( src, typeof(List<>).MakeGenericType(sourceItemType), typeof(List<>).MakeGenericType(destItemType) ); // 调用目标PagedList的带参构造 var constructor = ctx.DestinationType.GetConstructor(new[] { typeof(IEnumerable<>).MakeGenericType(destItemType), typeof(int), typeof(int), typeof(int) }); return constructor.Invoke(new[] { mappedItems, src.GetType().GetProperty("TotalCount").GetValue(src), src.GetType().GetProperty("CurrentPage").GetValue(src), src.GetType().GetProperty("PageSize").GetValue(src) }); });
方案3:自定义类型转换器
实现转换器手动处理转换逻辑,适合复杂场景:
单个实体对转换器
public class PagedListConverter : ITypeConverter<PagedList<Stuff>, PagedList<StuffDto>> { private readonly IMapper _mapper; public PagedListConverter(IMapper mapper) { _mapper = mapper; } public PagedList<StuffDto> Convert(PagedList<Stuff> source, PagedList<StuffDto> destination, ResolutionContext context) { var mappedItems = _mapper.Map<List<Stuff>, List<StuffDto>>(source); return new PagedList<StuffDto>(mappedItems, source.TotalCount, source.CurrentPage, source.PageSize); } }
注册转换器:
CreateMap<PagedList<Stuff>, PagedList<StuffDto>>() .ConvertUsing<PagedListConverter>();
泛型通用转换器
public class PagedListGenericConverter<TSource, TDestination> : ITypeConverter<PagedList<TSource>, PagedList<TDestination>> { private readonly IMapper _mapper; public PagedListGenericConverter(IMapper mapper) { _mapper = mapper; } public PagedList<TDestination> Convert(PagedList<TSource> source, PagedList<TDestination> destination, ResolutionContext context) { var mappedItems = _mapper.Map<List<TSource>, List<TDestination>>(source); return new PagedList<TDestination>(mappedItems, source.TotalCount, source.CurrentPage, source.PageSize); } }
注册泛型转换器:
CreateMap(typeof(PagedList<>), typeof(PagedList<>)) .ConvertUsing(typeof(PagedListGenericConverter<,>));
推荐选择
如果项目中大量使用泛型PagedList,优先选方案2的泛型构造配置或方案3的泛型转换器,无需为每个实体对单独配置;如果只是处理单个实体转换,方案2的单个配置更简洁。
内容的提问来源于stack exchange,提问作者BobbyDigital
相关产品推荐
相关产品推荐

