使用IValueResolver时AutoMapper为何抛出StackOverflowException异常?
问题分析与解决方案
你的代码确实错误使用了IValueResolver,核心问题是在Resolver中调用context.Mapper.Map时没有传递当前的ResolutionContext,导致AutoMapper无法跟踪已创建的实例,没法正确处理循环引用。
修复要点
- 在Resolver的
Resolve方法中,调用Map时必须传入当前的ResolutionContext,让AutoMapper在同一个映射会话中管理实例。 - 在映射配置中启用循环引用处理,使用
PreserveReferences()来告诉AutoMapper保留对象引用,避免循环引用引发的无限递归或重复创建对象。
修正后的完整代码
using AutoMapper; class Program { static void Main(string[] args) { A a = new A(); B b = new B(); a.B = b; b.List.Add(a); var mapper = new Mapper(new MapperConfiguration(cfg => { cfg.AddProfile<Profile1>(); })); var model = mapper.Map<AModel>(a); } } class A { public B B { get; set; } } class B { public List<A> List { get; set; } public B() { List = new List<A>(); } } class AModel { public BModel B { get; set; } } class BModel { public List<AModel> List { get; set; } } class Profile1 : Profile { public Profile1() { CreateMap<A, AModel>() .PreserveReferences() // 启用循环引用处理 .ForMember(x => x.B, o => o.MapFrom<ValueResolver1>()); CreateMap<B, BModel>() .PreserveReferences(); // 启用循环引用处理 } } class ValueResolver1 : IValueResolver<A, AModel, BModel> { public BModel Resolve(A source, AModel destination, BModel destMember, ResolutionContext context) { // 传递当前上下文,让AutoMapper跟踪实例 return context.Mapper.Map<BModel>(source.B, context); } }
原理说明
当你传递context给Map方法时,AutoMapper会在这个上下文的实例缓存中查找是否已经映射过source.B对应的目标对象。如果已经存在,就直接返回已有的实例,而不是创建新的,这样就能正确处理a -> b -> list包含a的循环引用,避免无限递归和重复创建对象。
内容的提问来源于stack exchange,提问作者K 1
相关产品推荐
相关产品推荐

