【问题标题】:How can I keep a ref to an object's state at a given time?如何在给定时间保持对对象状态的引用?
【发布时间】:2021-02-21 07:05:16
【问题描述】:

我的目标是在引发异常时将调用堆栈状态保存在文件中。但是我有一个主要的限制:我不能触及任何现有的代码。我的目标是在我不知道当前工作流程的情况下实现它。所以我可以在任何 C# 项目中使用它。

为此,我需要访问所有导致异常的嵌套方法以及所有方法的参数。

到目前为止,我使用 postsharp OnMethodBoundaryAspect,它允许我定义 OnEntry、OnSucess 和 OnException 方法,这些方法在输入、返回或引发异常时调用。很棒的是我可以在我想要的项目中使用postsharp.config 文件来应用这个方面。没有源代码修改,我只是将我的项目添加到解决方案中,一个配置文件,并在解决方案的每个项目中引用我的项目,我很高兴。使用它我可以维护自己的调用堆栈,并且可以保存对方法名称的引用和对方法参数的引用。

现在假设methodA 调用methodB,后者调用methodC

除了显然我使用了引用之外,我所做的一切都很好。因此,如果methodA 参数在引发异常之前在methodC 中被修改,当我序列化调用堆栈时,我们将看到一个调用堆栈,其中methodA 有一个错误值的参数(我们将看到该值设置在methodC)。

我想解决这个问题并考虑使用:

  1. 在 OnEntry 方法中进行深度克隆以复制所有方法参数,但这会导致糟糕的性能
  2. PostSharp LocationInterceptorAspect 但这需要付费许可
  3. VEH Hooking,但速度非常慢,使用deepcloning 可能会更快

有没有其他方法可以让我及时保存对象的状态,性能比deepcloning 更好,或者至少让我拦截对指定对象的所有修改(如 VEH 挂钩或 LocationInterceptor方面)?

PS:我不能使用IOnPropertyChange 或类似的东西,因为我无法触及任何现有的源代码,除非我可以在运行时实现它们,但我没有看到任何可能的地方。

【问题讨论】:

  • 您可以挂钩AppDomain.UnhandledException 事件,然后使用ExceptionObject 属性(转换/转换为异常)访问StackTrace 属性以获取堆栈跟踪,以及TargetSite 属性以访问引发异常的方法的 MethodBase。有了这些信息,您也许可以得到您想要的值,not likely though
  • 在 JIT 级别,对象不再存在,它都是内存位置,对象的“状态”是什么由旁观者决定。复制状态(如果必须的话,进行深度克隆)并动态应用增量压缩以消除未修改的状态将是降低成本的一种方法。那里没有免费的午餐;鉴于内存硬件没有实现不可变语义或廉价的通知触发器,没有本机机制或调试器可以做得比这更好。 VS 有 IntelliTrace/historical 调试功能,它可以快照一堆并且同样昂贵。

标签: c# callstack


【解决方案1】:

考虑到我不想在需要监控的对象中实现任何特定代码,我只有两个选择:

  1. 需要保存状态时的序列化或任何深度克隆方法(我在此解决方案中使用了 JSON.NET)

  2. 记录对对象进行的所有修改,以便在必要时撤消它们 => 在发生修改时收到通知我探索了所有这些技术:

    • 带有LocationInterceptionAspect 的Postsharp(不是免费的)
    • Harmony 2 允许拦截任何函数调用(在我的情况下是属性的 setter 函数),如果您可以丢弃任何字段更改,这是最简单和最简单的工作解决方案
    • VEH 挂钩,理论上可行,但速度极慢,由于其复杂性,我没有进行太多探索
    • Editing the MSIL code of a function 挂钩所有 stfld 指令。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    相关资源
    最近更新 更多