修改表达式树中的变量以检查递归深度——解决DelegateDecompiler引发的循环引用无限递归问题
解决DelegateDecompiler中depth参数未递减导致的循环引用问题
针对你遇到的这个depth变量在DelegateDecompiler反编译时没正确递减、最后引发无限循环栈溢出的问题,我整理了几个可行的解决方案方向,你可以逐一尝试:
1. 手动构建表达式树绕开反编译工具
既然自动反编译搞不定depth的递减逻辑,咱们可以直接手动写表达式树来实现DTO映射。这种方式能完全掌控参数传递的逻辑,不会被反编译的黑箱操作坑到。
举个思路:
- 给
Author到AuthorDTO写个静态方法,返回Expression<Func<Author, int, AuthorDTO>>类型的表达式树,在树里明确把depth-1传给Book的映射表达式。 - 同理给
Book到BookDTO写对应的表达式树方法,确保Author的映射用的是depth-1。 - 最后直接用
Queryable.Select把这些表达式树应用到你的IQueryable<Author>上,替代原来的CustomMapper.ProjectTo和反编译步骤。
虽然写表达式树有点繁琐,但胜在逻辑完全可控,彻底避开反编译的问题。
2. 把递归映射改成迭代式分层处理
既然递归+反编译出了问题,咱们可以换个思路,用迭代的方式分层映射数据:
- 先把所有需要的
Author和关联Book数据查出来(用Include或者Join都可以) - 先处理第一层:把
depth=2的Author转换成AuthorDTO,同时把所有关联的Book收集起来 - 再处理第二层:把这些
Book转换成BookDTO,此时depth=1,只需要关联回对应的AuthorDTO,不要再反向引用Author的完整DTO - 最后手动把
BookDTO集合关联到对应的AuthorDTO的Books字段里
这种方式完全避开了递归,自然就不会有depth不递减的问题,适合数据层级不深的场景。
3. 调整DelegateDecompiler的使用姿势
如果不想放弃DelegateDecompiler,可以试试这几个小调整:
- 先检查
[Computed]特性的使用是否正确,有没有哪里漏掉导致depth参数没被反编译工具识别到。 - 临时把
depth从方法参数改成静态字段(注意线程安全!),调用ProjectTo前设置初始值,映射方法里直接递减这个静态字段,看看能不能绕开反编译的参数处理问题。 - 要是你有看源码的能力,可以去翻DelegateDecompiler的源码,找找它处理参数递减的逻辑漏洞,自己整个补丁或者扩展来修复这个问题。
4. 换成成熟的投影映射库
与其自己折腾自定义映射+反编译,不如直接用原生支持IQueryable投影、还能处理循环引用的成熟库:
- AutoMapper:它的
ProjectTo方法原生支持IQueryable投影,还能通过MaxDepth配置控制映射层级,完美避免循环引用,根本不需要DelegateDecompiler。 - Mapster:性能比AutoMapper还优秀,同样支持
IQueryable投影,也有层级控制的配置,处理这种关联实体的DTO映射非常顺手。
这些库已经把各种边缘情况都处理好了,能省不少自己维护映射逻辑的精力。
内容的提问来源于stack exchange,提问作者Niels
相关产品推荐
相关产品推荐

