【问题标题】:How do I get the executing object for a stackframe?如何获取堆栈帧的执行对象?
【发布时间】:2009-05-20 17:50:17
【问题描述】:

使用反射时,可以使用 System.Diagnostics.StackTrace 获取调用堆栈(除此之外,由于 JIT 优化,它可能是一个粗略的近似值)并检查包含的 StackFrame 对象。

如何获取对堆栈帧中的方法正在其上执行的对象(this 指针)的引用?

我知道我可以通过在堆栈帧对象上调用 GetMethod() 来获取 MethodBase,但我正在寻找的是类似于 GetObject() 的东西(如果方法是静态的,它自然会返回 null) .似乎只能查询堆栈帧对象以获取静态确定的信息,例如方法信息、原始文件等。

VS 调试器知道(尽管它可能使用另一种获取调用堆栈跟踪的方法),因为可以双击调用堆栈窗口中的任何堆栈帧并查看本地和类字段的值。

编辑: 澄清一下:我想要调用该方法的 object instance。即:如果方法 Foo() 在调用堆栈上的某处对象实例 A 上调用,并且它级联到我执行堆栈跟踪的方法,我想从执行堆栈跟踪的位置获取对 A 的引用。 (不是方法基的声明类型)

【问题讨论】:

    标签: c# reflection stack-trace stack-frame


    【解决方案1】:

    我很确定这是不可能的。原因如下:

    1. 这可能会破坏类型安全,因为任何人都可以查找框架、获取对象,而不管他们在哪个 AppDomain\Thread 上执行或拥有权限。

    2. 'this'(C#)标识符实际上只是实例方法的一个参数(第一个),所以实际上静态方法和实例方法之间没有区别,编译器会发挥它的魔力将正确的this 传递给实例方法,这当然意味着您需要访问所有方法参数才能获取this 对象。 (StackFrame 不支持)

    可能通过使用unsafe 代码来获取实例方法的第一个参数的指针,然后将其转换为正确的类型,但我不知道如何做到这一点,只是一个想法。

    顺便说一句,您可以想象实例方法在被编译为类似于 C# 3.0 扩展方法后,它们将this 指针作为它们的第一个参数。

    【讨论】:

    • 我知道 this 指针是由调用者传递给调用堆栈上的被调用方法的,这就是为什么不存在的 GetObject() 如果它是静态方法会返回 null 的原因,以及实例方法中的规范“this”指针。但是,我同意您的 #1 论点,除了通过设计要求适当的许可可以轻松地限制对对象的访问。
    • 真正的问题是 StackFrame 只是关于您的代码的一些元数据,它不是您的代码的实时版本。
    • 正如我所担心的那样。但我希望还有其他课程可以使用。
    【解决方案2】:

    可以获得对thiscall 对象的引用,但不能仅使用 .NET 代码。必须涉及本机代码。即使使用动态类和 System.Relection.Emit 命名空间,.NET 也没有工具来访问其他方法评估堆栈和参数。

    另一方面,如果你反汇编你的 .NET 方法,你可以看到这个引用根本没有在物理堆栈上传递。 Thiscall 引用存储在 ECX(RCX for x64) 寄存器中。因此,可以从您的方法爬上堆栈到要从中获取thiscall 对象的方法。然后在该方法的机器代码中查找将寄存器ECX(RCX)保存在堆栈中的指令,并从该指令中获取该引用所在的相对地址。

    当然,爬升的方法在x32和x64应用中是有很大区别的。要生成这样的函数,您不仅必须使用 C#,还必须使用汇编代码,并记住 x64 下不允许内联汇编;它必须是一个完整的汇编模块。

    【讨论】:

      【解决方案3】:

      我不确定我是否完全理解你想要什么,但如果你想知道某个堆栈帧的方法声明的类型,我认为这段代码会返回:

      StackTrace trace = new StackTrace();    
      Type methodOwner = trace.GetFrame(0).GetMethod().DeclaringType;
      

      您当然需要传递您感兴趣的帧的索引(我以 0 为例)。

      【讨论】:

      • 我认为他指的是实例,而不是类型。
      • 是的,'object' 表示一个类型的实例;)
      • 是的,我意识到了(你的问题其实很清楚;我想我有点累了……)
      • 太棒了!就我而言,我只想要类型。
      猜你喜欢
      • 2014-07-22
      • 1970-01-01
      • 2019-02-19
      • 2011-04-19
      • 2018-02-23
      • 2015-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多