AutoMapper: What is the difference between MapFrom and ResolveUsing?

Ignoring the ResolveUsing overloads that take an IValueResolver, and looking only at these 2 methods:

void ResolveUsing(Func<TSource, object> resolver);
void MapFrom<TMember>(Expression<Func<TSource, TMember>> sourceMember);

The main difference between these 2 seems to be that ResolveUsing takes a Func<TSource, object> , whereas MapFrom takes an Expression<Func<TSource, TMember>> .

However in client code that actually uses one of these methods with a lambda expression, they seem to be interchangeable:

Mapper.CreateMap<SourceType, DestType>() // uses ResolveUsing
   .ForMember(d => d.DestPropX, o => o.ResolveUsing(s => s.SourcePropY));

Mapper.CreateMap<SourceType, DestType>() // uses MapFrom
   .ForMember(d => d.DestPropX, o => o.MapFrom(s => s.SourcePropY));

So what ultimately is the difference between the above 2 choices? Is one faster than the other? Is one a better choice than the other and if so, when / why?


In the past I had a long email exchange on the mailing list with the author of Automapper. MapFrom will do null checks all the way trough the expression:

So you can do opt => opt.MapFrom(src => src.SomeProp.Way.Down.Here.Somewhere) and each level will get checked for nulls (as it already does for flattening).


I just did some benchmarks using the new C# 6 null conditional operator ?.

Consider the following scenario: class A has a child class B , which has a child C , whose Name property we want to flatten into a DTO. I tested two variants:

// using mapfrom
CreateMap<MapFromA, MapFromADto>()
    .ForMember(dto => dto.Name, o => o.MapFrom(a => a.B.C.Name));

// using resolveusing with elvis
CreateMap<ResolveUsingX, ResolveUsingXDto>()
    .ForMember(dto => dto.Name, o => o.ResolveUsing(x => x.Y?.Z?.Name));

I called _mapper.Map<ResolveUsingXDto>(x); or _mapper.Map<MapFromADto>(a); for 1000 different ResolveUsingX x and MapFromA a and took the time using a System.Diagnostics.StopWatch . Here are my results:

Distinct elements per batch: 1000; # batches for average: 25

A->B->C.Name, C is never null.
MapForm - average time taken for 1000x: 5527,84 ticks = 1,44 ms.
ResolveUsing - average time taken for 1000x: 5479,76 ticks =  1,4 ms.

A->B->C.Name, C is null 1/3 of the time.
MapForm - average time taken for 1000x: 72924,4 ticks = 27,44 ms.
ResolveUsing - average time taken for 1000x: 5351,2 ticks =  1,48 ms.

A->B->C.Name, C is null 1/2 of the time.
MapForm - average time taken for 1000x: 107016,92 ticks = 40,52 ms.
ResolveUsing - average time taken for 1000x: 5835,32 ticks =  1,56 ms.

A->B->C.Name, C is null 2/3 of the time.
MapForm - average time taken for 1000x: 141437,96 ticks = 53,64 ms.
ResolveUsing - average time taken for 1000x: 5789,72 ticks =  1,56 ms.

MapFrom has to catch NullReferenceExceptions, which is slower than ResolveUsing with the elvis operator ?.


MapFrom has a few extra smarts. For example (from the mailing list):

In MapFrom, I try to be smart about digging in to child properties (much like the normal flattening does). MapFrom is an attempt to mimic flattening, with an added bit of allowing redirection. ResolveUsing doesn't have this behavior.

I'm not sure if this is fully documented anywhere (apart from in the source code).

链接地址: http://www.djcxy.com/p/37382.html

上一篇: 嵌套映射的AutoMapper扁平化要求定制解析器

下一篇: AutoMapper:MapFrom和ResolveUsing有什么区别?