C#中Calculate函数内GetExpression多次执行,求排查循环/递归问题
这种隐性的重复调用确实头疼,尤其是看着日志里GetExpression()反复跑却抓不到触发根源的时候。结合你提到的C#代码场景,我整理了几个逐步排查的方向:
先打全调用栈日志,理清触发路径
别只盯着Calculate()内部的直接调用,在GetExpression()方法的开头加一行调用栈日志:Console.WriteLine($"GetExpression()被调用,调用栈:{new System.Diagnostics.StackTrace().ToString()}");这样每次GetExpression()执行时,你能完整看到它是从哪个方法、哪一行触发的——是Calculate()里的循环迭代导致的?还是某个被调用的函数又回调了Calculate()形成递归?甚至会不会是DataSet的自动绑定逻辑间接触发的?调用栈会把整个调用链明明白白给你列出来。
检查Calculate()内部的循环/分支逻辑
你的代码开头是public DataSet Calculate(int compI...,大概率里面有遍历DataSet行、或者处理集合的循环逻辑?比如遍历DataRow时,每次迭代都调用了GetExpression()?哪怕是条件判断里的调用,也可能因为循环反复触发。可以在Calculate()的循环入口、每次调用GetExpression()的前后加日志,记录循环次数、当前处理的对象ID,对比GetExpression()的调用日志,就能看出是不是循环导致的重复。排查间接递归的可能性
递归不一定是Calculate()直接调用自己,也可能是间接闭环:比如Calculate()调用A(),A()调用B(),B()又绕回调用Calculate()。这时候调用栈日志会显示重复的方法序列,比如Calculate() → A() → B() → Calculate() → ...。另外也要检查GetExpression()本身会不会触发业务逻辑回调——比如它处理表达式时,有没有调用某个计算方法,而那个方法又触发了Calculate()?检查DataSet相关的事件绑定
如果你在Calculate()里修改了DataSet的数据,比如更新DataRow的值,那DataSet的RowChanged、ColumnChanged这类事件可能会被触发。如果事件处理程序里又调用了Calculate()或者GetExpression(),就会形成循环触发。可以暂时注释掉DataSet的事件绑定代码,看看GetExpression()的调用次数会不会骤降,验证这个可能性。用调试工具逐行跟踪
光看日志不够的话,直接用VS的调试功能:在GetExpression()的第一行打个断点,每次触发断点时,查看「调用栈」窗口,同时观察Calculate()里的变量(比如循环计数器、传入的compI参数值、当前处理的DataRow)。如果是循环,变量会有规律的变化;如果是递归,调用栈会有嵌套的重复方法。
内容的提问来源于stack exchange,提问作者want_to_be_calm

