13

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

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

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

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

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

4

3 回答 3

7

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

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

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

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

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

于 2009-05-20T18:24:56.280 回答
3

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

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

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

于 2012-05-10T08:56:25.467 回答
-1

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

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

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

于 2009-05-20T18:05:45.417 回答