忽略采用IValueResolver的ResolveUsing
重载,并仅查看这两种方法:
void ResolveUsing(Func<TSource, object> resolver);
void MapFrom<TMember>(Expression<Func<TSource, TMember>> sourceMember);
这两者之间的主要区别似乎是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));
那么上述两种选择之间最终的区别是什么呢?一个比另一个快吗?是一个比另一个更好的选择,如果是,何时/为什么?
答案 0 :(得分:62)
过去我和Automapper的作者有一个long email exchange on the mailing list。 MapFrom将通过表达式一直进行空检查:
所以你可以
opt => opt.MapFrom(src => src.SomeProp.Way.Down.Here.Somewhere)
,每个级别都会被检查 for nulls(因为它已经用于展平)。
答案 1 :(得分:19)
我刚刚使用新的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));
我针对1000个不同的_mapper.Map<ResolveUsingXDto>(x);
和_mapper.Map<MapFromADto>(a);
致电ResolveUsingX x
或MapFromA 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
?.
答案 2 :(得分:9)
MapFrom
有a few extra smarts。例如(来自mailing list):
在MapFrom中,我试图聪明地挖掘子属性(很像普通的扁平化)。 MapFrom是一种模仿扁平化的尝试,增加了一些允许重定向的功能。 ResolveUsing没有这种行为。
我不确定这是否完全documented在任何地方(source code除外)。
答案 3 :(得分:1)
虽然在许多情况下都可以使用,但基于official documentation,LINQ预测会有所不同。详细说明可以在here找到。
长话短说:尽可能使用MapFrom。
答案 4 :(得分: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);