You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:57:42