AutoMapper:MapFrom和ResolveUsing有什么区别?
忽略ResolveUsing
重载,只看这两个方法:
void ResolveUsing(Func<TSource, object> resolver); void MapFrom<TMember>(Expression<Func<TSource, TMember>> sourceMember);
这两者之间的主要区别似乎是ResolveUsing
采用Func<TSource, object>
,而MapFrom采用Expression<Func<TSource, TMember>>
。
然而,在实际使用lambdaexpression式的客户端代码中,它们似乎是可以互换的:
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));
那么上述两个select之间的区别究竟是什么呢? 一个比另一个快吗? 是一个比另一个更好的select,如果是的话,何时/为什么?
在过去,我和Automapper的作者在邮件列表上进行了长时间的邮件交换 。 MapFrom将通过expression式一路完成空检查:
所以你可以做
opt => opt.MapFrom(src => src.SomeProp.Way.Down.Here.Somewhere)
并且每个关卡都会被检查为null(就像它已经展开的那样)。
我只是使用新的C#6 空条件运算符做了一些基准testing?.
考虑以下情况:类A
有一个子类B
,它具有一个子C
,其Name
属性我们想要变成一个DTO。 我testing了两个变种:
// using mapfrom CreateMap<MapFromA, MapFromADto>() .ForMember(dto => dto.Name, o => o.MapFrom(a => aBCName)); // using resolveusing with elvis CreateMap<ResolveUsingX, ResolveUsingXDto>() .ForMember(dto => dto.Name, o => o.ResolveUsing(x => xY?.Z?.Name));
我叫_mapper.Map<ResolveUsingXDto>(x);
或_mapper.Map<MapFromADto>(a);
对于1000个不同的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
更慢?.
MapFrom
有一些额外的智慧 。 例如(从邮件列表 ):
在MapFrom中,我试图聪明地挖掘儿童属性(很像正常的扁平化)。 MapFrom试图模仿扁平化,并增加了一些允许redirect的function。 ResolveUsing没有这种行为。
我不确定这是否完全logging在任何地方( 源代码除外)。
根据源代码, ResolveUsing
比较复杂。 源值可以是任何对象; 因此,您可以使用任何值来填充目标成员,例如通过“parsing”给定对象所获得的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);
尽pipe在许多情况下都可以使用,但是根据官方文档 ,在LINQ预测方面有所不同。 详细的解释可以在这里find。
长话短说:尽可能使用MapFrom。