Автоматическое сопоставление с использованием открытых обобщений и включение источника в оператор 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;
}