【发布时间】:2021-02-21 07:05:16
【问题描述】:
我的目标是在引发异常时将调用堆栈状态保存在文件中。但是我有一个主要的限制:我不能触及任何现有的代码。我的目标是在我不知道当前工作流程的情况下实现它。所以我可以在任何 C# 项目中使用它。
为此,我需要访问所有导致异常的嵌套方法以及所有方法的参数。
到目前为止,我使用 postsharp OnMethodBoundaryAspect,它允许我定义 OnEntry、OnSucess 和 OnException 方法,这些方法在输入、返回或引发异常时调用。很棒的是我可以在我想要的项目中使用postsharp.config 文件来应用这个方面。没有源代码修改,我只是将我的项目添加到解决方案中,一个配置文件,并在解决方案的每个项目中引用我的项目,我很高兴。使用它我可以维护自己的调用堆栈,并且可以保存对方法名称的引用和对方法参数的引用。
现在假设methodA 调用methodB,后者调用methodC。
除了显然我使用了引用之外,我所做的一切都很好。因此,如果methodA 参数在引发异常之前在methodC 中被修改,当我序列化调用堆栈时,我们将看到一个调用堆栈,其中methodA 有一个错误值的参数(我们将看到该值设置在methodC)。
我想解决这个问题并考虑使用:
- 在 OnEntry 方法中进行深度克隆以复制所有方法参数,但这会导致糟糕的性能
- PostSharp LocationInterceptorAspect 但这需要付费许可
- VEH Hooking,但速度非常慢,使用
deepcloning可能会更快
有没有其他方法可以让我及时保存对象的状态,性能比deepcloning 更好,或者至少让我拦截对指定对象的所有修改(如 VEH 挂钩或 LocationInterceptor方面)?
PS:我不能使用IOnPropertyChange 或类似的东西,因为我无法触及任何现有的源代码,除非我可以在运行时实现它们,但我没有看到任何可能的地方。
【问题讨论】:
-
您可以挂钩
AppDomain.UnhandledException事件,然后使用ExceptionObject属性(转换/转换为异常)访问StackTrace属性以获取堆栈跟踪,以及TargetSite属性以访问引发异常的方法的MethodBase。有了这些信息,您也许可以得到您想要的值,not likely though -
在 JIT 级别,对象不再存在,它都是内存位置,对象的“状态”是什么由旁观者决定。复制状态(如果必须的话,进行深度克隆)并动态应用增量压缩以消除未修改的状态将是降低成本的一种方法。那里没有免费的午餐;鉴于内存硬件没有实现不可变语义或廉价的通知触发器,没有本机机制或调试器可以做得比这更好。 VS 有 IntelliTrace/historical 调试功能,它可以快照一堆并且同样昂贵。