2013-02-14 64 views
38

忽略ResolveUsing重載採取IValueResolver,並且僅在這2種方法尋找:AutoMapper:MapFrom和ResolveUsing有什麼區別?

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

這些2之間的主要差別似乎是ResolveUsing需要Func<TSource, object>,而MapFrom需要一個Expression<Func<TSource, TMember>>

然而,在實際使用的這些方法lambda表達式一個客戶端代碼,他們似乎是可互換的:

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

那麼最終是上述2個選擇之間的區別?一個比另一個快嗎?一個是比另一個更好的選擇,如果是的話,何時/爲什麼?

+0

這個問題簡單地解決了我的另一個問題。 – 2015-07-01 15:42:20

回答

50

在過去,我有一個long email exchange on the mailing list與作者Automapper。 MapFrom會做null檢查一路低谷表達:

所以,你可以做opt => opt.MapFrom(src => src.SomeProp.Way.Down.Here.Somewhere)和每個級別將得到空值檢查 (因爲它已經這樣做了扁平化)。

+1

+1,這個鏈接非常有幫助,謝謝。 – danludwig 2013-02-15 12:34:52

+3

來自該鏈接的信息:'MapFrom'用於重定向源成員,例如'ForMember(dest => dest.Foo,opt => opt.MapFrom(src => src.Bar))''。 'MapFrom'具有所有展平的空檢查,因此可以將其視爲重定向平展算法。 'ResolveUsing'幾乎是其他任何東西,除了成員訪問之外的任何其他自定義邏輯。這是一個'Func <>'而不是'Expression >',所以你不會得到空的檢查。 – Mightymuke 2013-02-15 18:07:38

+1

[這個鏈接](http://blog.travisgosselin.com/automapper-mapfrom-vs-resolveusing/)解釋了當您的應用程序經常需要nulls屬性時使用'MapFrom'時可以看到的一些潛在的性能命中。 – EarlCrapstone 2015-11-24 21:57:20

7

MapFroma few extra smarts。例如(從mailing list):

在MapFrom,我自作聰明約在深入瞭解孩子的屬性(很像正常的扁平一樣)。 MapFrom試圖模仿扁平化,並增加了一些允許重定向的功能。 ResolveUsing沒有這種行爲。

我不知道這是否完全是documented任何地方(除了在source code)。

+1

那麼看起來只要你映射標量而不是複雜的對象,它們在功能上是相同的。我想知道是否由於MapFrom中的額外智能而導致「ResolveUsing」更快? – danludwig 2013-02-14 21:52:37

+1

可能,雖然我認爲沒有任何官方性能測試已經完成。如果它對你來說足夠重要,它不應該花費很長時間爲你的特定場景設置幾個測試。 – Mightymuke 2013-02-14 22:05:44

+1

不是那麼重要。我只是在所有使用其中一個的地方都打過電話,但沒有真正的一致性。想要變得不那麼無知,所以發佈了這個問題。 – danludwig 2013-02-15 12:33:57

0

根據源代碼,ResolveUsing比較複雜。源值可以是任何對象;因此,您可以使用任何想要填充目標成員的值,例如通過「解析」給定對象獲得的int或bool。然而,MapFrom只使用成員來映射。

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

我只是用新的C#6 null conditional operator?.

考慮以下情形做了一些基準測試:類A有一個子類B,其中有一個孩子C,我們要壓扁成其Name財產一個DTO。我測試了兩個變種:

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

我叫_mapper.Map<ResolveUsingXDto>(x);_mapper.Map<MapFromADto>(a); 1000不同ResolveUsingX xMapFromA a和使用System.Diagnostics.StopWatch花時間。下面是我的結果:

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已經趕上NullReferenceException異常,這是比慢ResolveUsing與貓王操作?.

0

雖然在很多情況下,都可以採用,基於official documentation是有區別的,當它來LINQ預測。詳細的解釋可以在here找到。

長話短說:儘可能使用MapFrom。