58

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?

Michał Powaga
  • 22,561
  • 8
  • 51
  • 62
danludwig
  • 46,965
  • 25
  • 159
  • 237

5 Answers5

72

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).

Sunny Milenov
  • 21,990
  • 6
  • 80
  • 106
  • 5
    Info from that link: `MapFrom` is intended for redirecting source members - things like `ForMember(dest => dest.Foo, opt => opt.MapFrom(src => src.Bar))`. `MapFrom` has all of the null-checking that flattening has, so it can be thought of as redirecting the flattening algorithm. `ResolveUsing` is for pretty much anything else, any additional custom logic beyond member access. It's a `Func<>` instead of an `Expression>`, so you don't get null checking. – Mightymuke Feb 15 '13 at 18:07
  • 1
    [This link](http://blog.travisgosselin.com/automapper-mapfrom-vs-resolveusing/) explains some of the potential performance hits that can be seen when using `MapFrom` when nulls properties are often expected in your application. – EarlCrapstone Nov 24 '15 at 21:57
  • When you're using a method as part of the mapping such as `src.PropA.Select(x => x...)`. If PropA is null then you get an exception. Use ResolveUsing in that scenario – wnbates Apr 30 '18 at 13:52
  • Perhaps you should also note that this is only possible when using simple expressions, as soon as you add a { block of code } the automatic null checking is no longer possible. – Peter Morris May 25 '18 at 14:56
  • 1
    From automapper 8.0, ResovleUsing was replaced by MapFrom. [updgrate guide](http://docs.automapper.org/en/stable/8.0-Upgrade-Guide.html#resolveusing) – Liang Jul 25 '19 at 07:22
  • Perhaps this is over-generalized but, with `MapFrom`, you get automatic safety checks, while with `ResolveUsing`, you must provide your own. If you know for sure you'll be dealing with nulls, `ResolveUsing` can be faster. Of course, since AutoMapper 8, `ResolveUsing` is no longer available. – Suncat2000 May 08 '20 at 12:10
23

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 ?.

Georg Patscheider
  • 9,357
  • 1
  • 26
  • 36
  • +1 This was a very useful benchmark. It shows the difference between exception handling and explicit null-checking. Hopefully, the new versions of AutoMapper use explicit null-checking, since `ResolveUsing` is no longer available. – Suncat2000 May 08 '20 at 12:13
9

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).

Mightymuke
  • 5,094
  • 2
  • 31
  • 42
  • 1
    So then it seems as long as you are mapping scalars and not complex objects, they are functionally the same. I wonder if `ResolveUsing` is faster because of the extra smarts in MapFrom.....? – danludwig Feb 14 '13 at 21:52
  • 1
    Possibly, although I don't think any official performance tests have been done. If its important enough for you, it shouldn't take you long to set up a couple of tests for your particular scenario. – Mightymuke Feb 14 '13 at 22:05
  • 1
    Not that important. I just have calls all over where one or the other is used, with no real consistency. Wanted to become less ignorant about it, so posted this question. – danludwig Feb 15 '13 at 12:33
1

Although in many situations either can be used, based on official documentation there is a difference when it comes to LINQ projections. Detailed explanation can be found here.

Long story short: use MapFrom whenever possible.

Aleksandar Pesic
  • 668
  • 7
  • 18
0

According to the source code, ResolveUsing is more complicated. The source value can be any object; therefore, you can use any value you want to fill the destination member, such as int or bool that you get by "Resolving" the given object. However, MapFrom only uses member to map from.

/// <summary>
/// Resolve destination member using a custom value resolver callback. Used instead of MapFrom when not simply redirecting a source member
/// This method cannot be used in conjunction with LINQ query projection
/// </summary>
/// <param name="resolver">Callback function to resolve against source type</param>
void ResolveUsing(Func<TSource, object> resolver);

/// <summary>
/// Specify the source member to map from. Can only reference a member on the <typeparamref name="TSource"/> type
/// This method can be used in mapping to LINQ query projections, while ResolveUsing cannot.
/// Any null reference exceptions in this expression will be ignored (similar to flattening behavior)
/// </summary>
/// <typeparam name="TMember">Member type of the source member to use</typeparam>
/// <param name="sourceMember">Expression referencing the source member to map against</param>
void MapFrom<TMember>(Expression<Func<TSource, TMember>> sourceMember);
leoly
  • 8,468
  • 6
  • 32
  • 33