AutoMapper – inheritance映射不​​起作用,相同的源,多个目标

我可以在AutoMapper(v2.2)中使用具有相同Source类型但不同Destination类型的映射的inheritance映射吗?

我有这个基本情况(真正的类有更多的属性):

public abstract class BaseViewModel { public int CommonProperty { get; set;} } public class ViewModelA : BaseViewModel { public int PropertyA { get; set; } } public class ViewModelB : BaseViewModel { public int PropertyB { get; set; } } 

ViewModelAViewModelB是同一个Entity类的不同表示:

 public class Entity { public int Property1 { get; set; } public int Property2 { get; set; } public int Property3 { get; set; } } 

我想为每个ViewModel重用相同的BaseViewModel映射,例如:

 Mapper.CreateMap() .Include() .Include() .ForMember(x => x.CommonProperty, y => y.MapFrom(z => z.Property1)); Mapper.CreateMap() .ForMember(x => x.PropertyA, y => y.MapFrom(z => z.Property2)); Mapper.CreateMap() .ForMember(x => x.PropertyB, y => y.MapFrom(z => z.Property3)); 

但不幸的是,这似乎不起作用。 这些电话是这样的:

 var model = Mapper.Map(entity); 

导致具有PropertyA映射的model ,但不是CommonProperty 。 我相信我正在遵循https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance中的示例,但我担心使用相同的Source类型创建多个地图会使AutoMapper绊倒。

任何见解? 我喜欢将Base类映射分组在一起的想法,但这似乎不起作用。

不幸的是,在这种情况下,AutoMapper似乎只为每个源类型注册一个子类映射,最后一个( ViewModelB )。 这可能是为了与并行层次结构一起使用,而不是使用单一源类型。

要解决此问题,您可以在扩展方法中封装公共映射:

 public static IMappingExpression MapBaseViewModel(this IMappingExpression map) where TDestination : BaseViewModel { return map.ForMember(x => x.CommonProperty, y => y.MapFrom(z => z.Property1)); } 

并在单个子类映射中使用它:

 Mapper.CreateMap() .MapBaseViewModel() .ForMember(x => x.PropertyA, y => y.MapFrom(z => z.Property2)); Mapper.CreateMap() .MapBaseViewModel() .ForMember(x => x.PropertyB, y => y.MapFrom(z => z.Property3)); 

哟可以这样做

  CreateMap() .InheritMapping(x => { x.IncludeDestinationBase(); }); 

有扩展代码

 public static class MapExtensions { public static void InheritMapping( this IMappingExpression mappingExpression, Action> action) { InheritMappingExpresssion x = new InheritMappingExpresssion(mappingExpression); action(x); x.ConditionsForAll(); } private static bool NotAlreadyMapped(Type sourceType, Type desitnationType, ResolutionContext r, Type typeSourceCurrent, Type typeDestCurrent) { var result = !r.IsSourceValueNull && Mapper.FindTypeMapFor(sourceType, desitnationType).GetPropertyMaps().Where( m => m.DestinationProperty.Name.Equals(r.MemberName)).Select(y => !y.IsMapped() ).All(b => b); return result; } public class InheritMappingExpresssion { private readonly IMappingExpression _sourcExpression; public InheritMappingExpresssion(IMappingExpression sourcExpression) { _sourcExpression = sourcExpression; } public void IncludeSourceBase( bool ovverideExist = false) { Type sourceType = typeof (TSourceBase); Type destinationType = typeof (TDestination); if (!sourceType.IsAssignableFrom(typeof (TSource))) throw new NotSupportedException(); Result(sourceType, destinationType); } public void IncludeDestinationBase() { Type sourceType = typeof (TSource); Type destinationType = typeof (TDestinationBase); if (!destinationType.IsAssignableFrom(typeof (TDestination))) throw new NotSupportedException(); Result(sourceType, destinationType); } public void IncludeBothBases() { Type sourceType = typeof (TSourceBase); Type destinationType = typeof (TDestinatioBase); if (!sourceType.IsAssignableFrom(typeof (TSource))) throw new NotSupportedException(); if (!destinationType.IsAssignableFrom(typeof (TDestination))) throw new NotSupportedException(); Result(sourceType, destinationType); } internal void ConditionsForAll() { _sourcExpression.ForAllMembers(x => x.Condition(r => _conditions.All(c => c(r))));//указываем что все кондишены истинны } private List> _conditions = new List>(); private void Result(Type typeSource, Type typeDest) { _sourcExpression.BeforeMap((x, y) => { Mapper.Map(x, y, typeSource, typeDest); }); _conditions.Add((r) => NotAlreadyMapped(typeSource, typeDest, r, typeof (TSource), typeof (TDestination))); } } }