IValueResolverを受け取るResolveUsing
オーバーロードを無視し、次の2つのメソッドのみを確認します。
void ResolveUsing(Func<TSource, object> resolver);
void MapFrom<TMember>(Expression<Func<TSource, TMember>> sourceMember);
これら2つの主な違いは、ResolveUsing
がFunc<TSource, object>
、MapFromはExpression<Func<TSource, TMember>>
。
ただし、ラムダ式でこれらのメソッドのいずれかを実際に使用するクライアントコードでは、これらは互換性があるようです。
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つの選択肢の違いは最終的に何でしょうか?一方が他方より速いですか?一方が他方よりも良い選択であり、もしそうなら、いつ/なぜですか?
過去には、Automapperの作成者と メーリングリストでの長いメール交換 がありました。 MapFromは、式全体でnullチェックを実行します。
したがって、
opt => opt.MapFrom(src => src.SomeProp.Way.Down.Here.Somewhere)
を実行すると、各レベルでnullのチェックが行われます(既にフラット化の場合と同様)。
新しいC#6を使用していくつかのベンチマークを行いました null条件演算子 _?.
_
次のシナリオを考えてみましょう。クラスA
には子クラスB
があり、これには子C
があり、そのName
プロパティはDTOにフラット化します。 2つのバリアントをテストしました。
_// 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));
_
1000個の_ResolveUsingX x
_および_MapFromA a
_に対して_mapper.Map<ResolveUsingXDto>(x);
または_mapper.Map<MapFromADto>(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
はNullReferenceExceptionsをキャッチする必要があり、elvis演算子_?.
_を使用したResolveUsing
よりも遅い
MapFrom
には いくつかの特別なスマート があります。たとえば( メーリングリスト から):
MapFromでは、(通常のフラット化と同様に)子プロパティを掘り下げることを賢くしようとします。 MapFromは、リダイレクトを許可するビットを追加して、フラット化を模倣する試みです。 ResolveUsingにはこの動作はありません。
ソースコードによると、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);