Автоматическое сопоставление с использованием открытых обобщений и включение источника в оператор ForMember

Недавно я обновил Automapper 4.2.1 до 5.1.1, и у меня возникают проблемы с ранее действительным отображением, включающим открытые дженерики.

Ранее, в конфигурации с автоматом, у меня была следующая конфигурация открытого общего отображения

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

Это работает в Automapper 4, но не в 5 с InvalidOperaionException при попытке нанести на карту через IMapper.Map<TDestination>(source), Похоже, что происходит сбой при выполнении сопоставления элементов ForMember операция с сообщением об исключении " Последовательность не содержит соответствующий элемент "

Как отражено в примере реализации кода ниже IPager<TSource> инвентарь IEnumerable<TSource> и Items собственностью ModelPager<TDestination> является IEnumerable<TDestination> поэтому актерский состав должен быть действительным. и существует действительное отображение для каждого TSource в TDestination

CreateMap<TSource, TDestination>();

Интерфейс IPager

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

    int PageCount { get; }

    int PageSize { get; }

    int TotalItems { get; }
}

Реализация 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

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

Как правильно отобразить это в Automapper 5, не отказываясь ни от открытых открытых обобщений, явно отображая каждое возможное сопоставление, ни используя настраиваемый открытый преобразователь универсальных типов, который потребовал бы от меня вручную сопоставить все свойства и использовать отражение для разрешения открытых типов для назначение?

1 ответ

Решение

Учитывая, что это выглядит как ошибка ( AutoMapper # 1624), можно обойти эту проблему с помощью специального открытого универсального TypeConverter это не требует отражения.

Отображение должно быть изменено на что-то вроде

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

с обычаем 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;
    }
Другие вопросы по тегам