2016-08-16 4 views
3

J'ai récemment effectué une mise à niveau d'Automapper 4.2.1 vers la version 5.1.1 et je rencontre des problèmes avec un mappage précédemment valide impliquant des génériques ouverts.Automatisation à l'aide de génériques ouverts et inclusion de la source dans une instruction ForMember

Auparavant, dans la configuration de automapper, j'ai eu la configuration de mappage générique ouverte suivante

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

Cela fonctionne dans 4 Automapper mais échoue dans 5 avec un InvalidOperaionException lors d'une tentative de la carte via IMapper.Map<TDestination>(source). Il semble à l'échec lors de l'exécution de la mise en correspondance des ArticlesForMember opération avec un message d'exception de « séquence ne contient aucun élément correspondant »

Comme il est indiqué dans le code de mise en œuvre d'exemple ci-dessous IPager<TSource> implémente IEnumerable<TSource> et la propriété Items de ModelPager<TDestination> est un IEnumerable<TDestination> alors la distribution devrait être valide. et il existe un mappage valide pour chaque TSource à TDestination

CreateMap<TSource, TDestination>(); 

IPager Interface

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

    int PageCount { get; } 

    int PageSize { get; } 

    int TotalItems { get; } 
} 

IPager application

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

Quelle est la bonne façon de mapper ce dans Automapper 5 sans soit abandonner open generics en cartographiant explicitement chaque mappage possible, ou en utilisant un type converter générique ouvert personnalisée qui me obligerait à mapper manuellement toutes les propriétés et la réflexion de l'utilisation à résoudre les types ouverts pour l'affectation?

+2

Cela ressemble à un bug, vous pouvez ouvrir un problème GitHub? –

+1

@JimmyBogard peut faire – rheone

+1

Problème [# 1624] (https://github.com/AutoMapper/AutoMapper/issues/1624) a été soumis – rheone

Répondre

3

Compte tenu de ce qui semble être un bug (AutoMapper #1624), un travail autour peut être fait avec un TypeConverter que générique ouvert personnalisé ne nécessite réflexion.

La cartographie doit être changé quelque chose le long des lignes de

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

avec une coutume 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; 
    }