简体   繁体   English

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

[英]Automapping using open generics and including the source in a ForMember statement

I've recently upgraded from Automapper 4.2.1 to 5.1.1 and am having issues with a previously valid mapping involving open generics. 我最近从Automapper 4.2.1升级到5.1.1,并且遇到了涉及开放泛型的先前有效映射的问题。

Previously, within the automapper configuration, I had the following open generic mapping configuration 以前,在automapper配置中,我有以下开放的通用映射配置

CreateMap(typeof(IPager<>), typeof(ModelPager<>))
    .ForMember("Items", e => e.MapFrom(o => (IEnumerable) o));

This works in Automapper 4 but fails in 5 with a InvalidOperaionException when attempting to map via IMapper.Map<TDestination>(source) . 这在Automapper 4中有效,但在尝试通过IMapper.Map<TDestination>(source)进行映射时,在5中因InvalidOperaionException而失败。 It appears to fail when executing the mapping of the Items ForMember operation with an exception message of " Sequence contains no matching element " 在执行Items ForMember操作的映射时,它似乎失败,并显示“ Sequence contains no matching element ”的异常消息

As reflected in the example implementation code below IPager<TSource> implements IEnumerable<TSource> , and the Items property of ModelPager<TDestination> is an IEnumerable<TDestination> so the cast should be valid. 如下面的示例实现代码所示, IPager<TSource>实现IEnumerable<TSource>ModelPager<TDestination>Items属性是IEnumerable<TDestination>因此IEnumerable<TDestination>应该是有效的。 and there exist a valid mapping for each TSource to TDestination 并且存在每个TSourceTDestination的有效映射

CreateMap<TSource, TDestination>();

IPager interface IPager界面

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

    int PageCount { get; }

    int PageSize { get; }

    int TotalItems { get; }
}

IPager implementation 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();
}

ModelPager ModelPager

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; }
}

What is the proper way to map this in Automapper 5 without either abandoning open generics by explicitly mapping each possible mapping, or by using a custom open generic type converter that would require me to manually map all properties and use reflection to resolve the open types for assignment? 在Automapper 5中通过显式映射每个可能的映射放弃开放泛型 ,或者使用自定义开放泛型类型转换器 ,需要我手动映射所有属性并使用反射来解析开放类型,在Automapper 5中映射它的正确方法是什么分配?

Given this looks to be a bug ( AutoMapper #1624 ), a work around can be done with a custom open generic TypeConverter that does not require reflection. 鉴于这看起来是一个错误( AutoMapper#1624 ),周围可以用自定义开放式泛型来完成工作TypeConverter 不需要反思。

The mapping should be changed to something along the lines of 映射应该改为某些行

CreateMap(typeof(IPager<>), typeof(ModelPager<>))
    .ConvertUsing(typeof(PagerToModelPagerConverter<,>));

with a custom ITypeConverter 使用自定义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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM