2013-02-14 16 views
38

Ignorando le ResolveUsing overload che accettano un IValueResolver, e guardando solo questi 2 metodi:AutoMapper: qual è la differenza tra MapFrom e ResolveUsing?

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

La principale differenza tra questi 2 sembra essere che ResolveUsing prende un Func<TSource, object>, mentre MapFrom prende un Expression<Func<TSource, TMember>>.

Tuttavia nel codice client che in realtà utilizza uno di questi metodi con un'espressione lambda, che sembrano essere intercambiabili:

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

Quindi quello che alla fine è la differenza tra i suddetti 2 scelte? È uno più veloce dell'altro? È una scelta migliore rispetto all'altra e se sì, quando/perché?

+0

Questa domanda mi ha semplicemente risolto un altro problema. –

risposta

50

In passato avevo uno long email exchange on the mailing list con l'autore di Automapper. MapFrom farà controlli nulli tutta la strada Trough l'espressione:

modo da poter fare opt => opt.MapFrom(src => src.SomeProp.Way.Down.Here.Somewhere) e ogni livello sarà ottenere controllato per valori nulli (come fa già per appiattimento).

+1

+1, questo collegamento è estremamente utile, grazie. – danludwig

+3

Informazioni da quel collegamento: 'MapFrom' è destinato al reindirizzamento di membri di origine, ad esempio' ForMember (dest => dest.Foo, opt => opt.MapFrom (src => src.Bar)) '. 'MapFrom' ha tutto il controllo Null che ha l'appiattimento, quindi può essere pensato come reindirizzare l'algoritmo di appiattimento. 'ResolveUsing' è praticamente qualsiasi altra cosa, qualsiasi logica aggiuntiva aggiuntiva oltre l'accesso ai membri. È un 'Func <>' invece di un 'Expression >', quindi non si ottiene il controllo Null. – Mightymuke

+1

[Questo collegamento] (http://blog.travisgosselin.com/automapper-mapfrom-vs-resolveusing/) spiega alcuni dei potenziali risultati delle prestazioni che possono essere visti quando si utilizza 'MapFrom' quando le proprietà dei valori nulli sono spesso previste nell'applicazione . – EarlCrapstone

7

MapFrom ha a few extra smarts. Per esempio (dal mailing list):

In MapFrom, cerco di essere intelligenti su scavare per proprietà secondarie (molto simile al normale appiattimento fa). MapFrom è un tentativo di simulare l'appiattimento, con un ulteriore vantaggio nel consentire il reindirizzamento. ResolveUsing non ha questo comportamento.

Non sono sicuro se questo è completamente documented ovunque (a parte nello source code).

+1

Quindi sembra che se si mappano scalari e non oggetti complessi, sono funzionalmente uguali. Mi chiedo se 'ResolveUsing' è più veloce a causa delle ulteriori capacità in MapFrom .....? – danludwig

+1

Forse, anche se non penso che siano stati fatti test ufficiali sulle prestazioni. Se è abbastanza importante per te, non dovrebbe richiedere molto tempo per impostare un paio di test per il tuo scenario particolare. – Mightymuke

+1

Non è così importante. Ho solo chiamate ovunque dove viene usata l'una o l'altra, senza una vera coerenza. Volevo diventare meno ignorante a riguardo, quindi ho postato questa domanda. – danludwig

0

Secondo il codice sorgente, ResolveUsing è più complicato. Il valore di origine può essere qualsiasi oggetto; pertanto, puoi utilizzare qualsiasi valore che desideri riempire il membro di destinazione, ad esempio int o bool che ottieni con "Resolving" dell'oggetto specificato. Tuttavia, MapFrom utilizza solo un membro da cui mappare.

/// <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); 
13

ho appena fatto alcuni benchmark con il nuovo C# 6 null conditional operator?.

Si consideri il seguente scenario: classe A ha una classe figlia B, che ha un figlio C, la cui Name proprietà vogliamo appiattire in un DTO. Ho provato due varianti:

// 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)); 

ho chiamato _mapper.Map<ResolveUsingXDto>(x); o _mapper.Map<MapFromADto>(a); per 1000 diversi ResolveUsingX x e MapFromA a e ha preso il tempo utilizzando un System.Diagnostics.StopWatch.Qui ci sono i miei risultati:

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 deve prendere NullReferenceExceptions, che è più lento rispetto ResolveUsing con l'operatore elvis ?.

0

Anche se in molte situazioni sia può essere utilizzato, in base a official documentation c'è una differenza quando si arriva alle proiezioni LINQ. Spiegazione dettagliata può essere trovata here.

Per farla breve: utilizzare MapFrom quando possibile.