使用开放泛型自动映射并在 ForMember 语句中包含源

rhe*_*one 5 generics automapper open-generics automapper-5

我最近从 Automapper 4.2.1 升级到 5.1.1,并且在使用涉及开放泛型的先前有效映射时遇到问题。

以前,在 automapper 配置中,我有以下打开的通用映射配置

CreateMap(typeof(IPager<>), typeof(ModelPager<>))
    .ForMember("Items", e => e.MapFrom(o => (IEnumerable) o));
Run Code Online (Sandbox Code Playgroud)

这在 Automapper 4 中有效,但在InvalidOperaionException尝试通过IMapper.Map<TDestination>(source). 执行Items ForMember操作的映射时似乎失败,异常消息为“ Sequence contains no matching element ”

这反映在示例实现代码下面 IPager<TSource>器具IEnumerable<TSource>,以及Items财产ModelPager<TDestination>是IEnumerable<TDestination>如此铸造应该是有效的。并且存在每个TSource到的有效映射TDestination

CreateMap<TSource, TDestination>();
Run Code Online (Sandbox Code Playgroud)

网页界面

public interface IPager<out TItem> : IEnumerable<TItem>
{
    int CurrentPage { get; }

    int PageCount { get; }

    int PageSize { get; }

    int TotalItems { get; }
}
Run Code Online (Sandbox Code Playgroud)

IPager实现

public class Pager<TItem> : IPager<TItem>
{
    private readonly IEnumerable<TItem> _items;

    public Pager(IEnumerable<TItem> items,
                 int currentPage,
                 int pageSize,
                 int totalItems)
    {
        /// ... logic ... 
        this._items = items ?? Enumerable.Empty<TItem>();
        this.CurrentPage = currentPage;
        this.PageSize = pageSize;
        this.TotalItems = totalItems;
    }

    public int CurrentPage { get; }

    public int PageCount => (this.TotalItems + this.PageSize - 1) / this.PageSize;

    public int PageSize { get; }

    public int TotalItems { get; }

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();

    public IEnumerator<TItem> GetEnumerator() => this._items.GetEnumerator();
}
Run Code Online (Sandbox Code Playgroud)

模型寻呼机

public class ModelPager<TItem>
{
    public int CurrentPage { get; set; }

    public IEnumerable<TItem> Items { get; set; }

    public int PageCount { get; set; }

    public int PageSize { get; set; }

    public int TotalItems { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在 Automapper 5 中映射这个的正确方法是什么,而不是通过显式映射每个可能的映射来放弃开放泛型,或者使用自定义的开放泛型类型转换器,这需要我手动映射所有属性并使用反射来解析开放类型任务?

rhe*_*one 7

鉴于这看起来是一个错误(AutoMapper #1624TypeConverter ),可以使用不需要反射的自定义开放通用来完成解决方法。

映射应该更改为类似的内容

CreateMap(typeof(IPager<>), typeof(ModelPager<>))
    .ConvertUsing(typeof(PagerToModelPagerConverter<,>));
Run Code Online (Sandbox Code Playgroud)

与定制ITypeConverter

public class PagerToModelPagerConverter<TSource, TDestination> : ITypeConverter<IPager<TSource>, ModelPager<TDestination>>
{
    public ModelPager<TDestination> Convert(IPager<TSource> source,
                                            ModelPager<TDestination> destination,
                                            ResolutionContext context)
    {
        var list = source.ToList(); // avoid redundant iterations
        var itemMapping = context.Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(list);

        var modelPager = new ModelPager<TDestination>
                         {
                             CurrentPage = source.CurrentPage,
                             Items = itemMapping,
                             PageCount = source.PageCount,
                             PageSize = source.PageSize,
                             TotalItems = source.TotalItems
                         };

        return modelPager;
    }
Run Code Online (Sandbox Code Playgroud)