AutoMapper使用多个IValueResolvers时Resolve()方法的调用顺序问题
AutoMapper IValueResolver执行顺序问题解答
调用顺序异常的核心原因
AutoMapper执行映射时,成员映射的优先级和顺序不由你写ForMember的声明顺序决定,而是由目标类型(这里是Bar类)的属性获取顺序决定:
- 首先处理继承自父类的属性,再处理当前类声明的属性
- 同一层级的属性,默认顺序由.NET反射的
Type.GetProperties()返回顺序决定,部分.NET版本下会按属性名字母序排序,这也是你看到AssetResolver(对应Asset属性首字母为A)最先执行的原因 - 你观察到剩余Resolver执行顺序和声明顺序一致,只是刚好你的
Bar类中Name、HistName、Props三个属性的反射返回顺序和你写ForMember的顺序重合,属于巧合,不具备通用性
调整执行顺序的方案
- 方案1:显式自定义类型转换器(推荐)
如果你业务上要求多个Resolver必须按固定顺序执行,最稳妥的方式是放弃拆分多个成员级IValueResolver,改为实现ITypeConverter<Foo, Bar>,在Convert方法中按你需要的顺序显式调用各个Resolver的逻辑,示例代码如下:
注册映射时替换原有规则即可:public class FooToBarConverter : ITypeConverter<Foo, Bar> { private readonly NameResolver _nameResolver; private readonly HistNameResolver _histNameResolver; private readonly AssetResolver _assetResolver; private readonly PropsResolver _propsResolver; // 依赖注入各个Resolver public FooToBarConverter(NameResolver nameResolver, HistNameResolver histNameResolver, AssetResolver assetResolver, PropsResolver propsResolver) { _nameResolver = nameResolver; _histNameResolver = histNameResolver; _assetResolver = assetResolver; _propsResolver = propsResolver; } public Bar Convert(Foo source, Bar destination, ResolutionContext context) { var dest = destination ?? new Bar(); // 先处理普通字段映射 dest.Id = source.ID; dest.ActivityName = source.Name; // 按你需要的顺序调用Resolver逻辑 dest.Name = _nameResolver.Resolve(source, dest, dest.Name, context); dest.HistName = _histNameResolver.Resolve(source, dest, dest.HistName, context); dest.Asset = _assetResolver.Resolve(source, dest, dest.Asset, context); dest.Props = _propsResolver.Resolve(source, dest, dest.Props, context); return dest; } }CreateMap<Foo, Bar>().ConvertUsing<FooToBarConverter>(); - 方案2:调整目标类属性声明顺序(不推荐)
如果你使用的.NET版本下Type.GetProperties()严格按属性声明顺序返回,可以调整Bar类中属性的声明顺序,间接控制Resolver的调用顺序。但该方式依赖.NET运行时的反射实现,跨版本/跨平台可能出现异常,不建议生产环境使用。
内容的提问来源于stack exchange,提问作者Dayman75
相关产品推荐
相关产品推荐

