2009-05-20 65 views
11

使用反射時,可以使用System.Diagnostics.StackTrace獲取調用堆棧(除了它可以是由JIT優化造成的粗略近似)並檢查包含的StackFrame對象。如何獲取堆棧幀的執行對象?

我怎樣才能得到一個對象(this-pointer)的一個方法在棧框架正在執行的引用?我知道我可以通過調用堆棧框架對象上的GetMethod()來獲得MethodBase,但我正在尋找的東西是沿着GetObject()的行(如果方法是靜態的,它自然會返回null )。似乎堆棧框架對象只能查詢靜態確定的信息,如方法信息,原始文件等。

VS調試器知道(雖然它可能使用另一種獲取調用堆棧跟蹤的方法),就像一個可以雙擊調用堆棧窗口中的任何堆棧幀並查看本地和類字段的值。

編輯: 澄清:我想對象實例上被調用的方法。 I.e .:如果方法Foo()在調用堆棧某處的對象實例A上調用,並且它會級聯到我執行堆棧跟蹤的方法,我想從執行堆棧跟蹤的位置獲得對A的引用。 (不是方法庫的聲明類型)

回答

6

我很確定這是不可能的。這裏的原因:

  1. 這可能打破類型安全,因爲任何人都可以查找框架,獲取對象無論哪個應用程序域\線程,他們正在執行或他們的權限。 (C#)標識符實際上只是實例方法的一個參數(第一個),所以實際上靜態方法和實例方法之間沒有區別,編譯器會傳遞正確的this轉換爲實例方法,這當然意味着您需要訪問所有方法參數才能獲取this對象。 (這StackFrame不支持)

可能可以通過使用unsafe代碼來獲得的第一個參數的實例方法的指針,然後將其強制轉換爲正確的類型,但我不知道該怎樣認識要做到這一點,只是一個想法。

順便說一句,你可以想象編譯後的實例方法就像C#3.0擴展方法一樣,它們將this指針作爲它們的第一個參數。

-1

我不確定我完全理解你想要什麼,但是如果你想知道某個棧幀的方法被聲明的類型,我認爲這個代碼返回:

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

您當然需要通過您感興趣的框架的索引(我使用0作爲示例)。

+2

我認爲他是指實例,而不是類型。 – 2009-05-20 18:08:03

+0

是的,'對象'意味着一個類型的實例;) – 2009-05-21 10:24:37

3

有可能獲得對thiscall對象的引用,但不能使用.NET代碼。必須涉及本機代碼。即使使用動態類和System.Relection.Emit命名空間.NET也沒有工具來訪問另一個方法評估堆棧和參數。

另一方面,如果你反彙編你的.NET方法,你可以看到這個引用沒有在物理堆棧上傳遞。取而代之的是Thiscall參考存儲在ECXRCX for x64)寄存器中。所以有可能從你的方法上爬到你想要獲得thiscall對象的方法。然後在該方法的機器代碼內部查找用於將寄存器ECX(RCX)保存在堆棧中的指令,並從那個引用所在的指令相關地址中獲取。

當然,在x32和x64應用中,攀爬的方法是嚴重不同的。要產生這樣的功能,您不僅必須使用C#,而且還要使用匯編代碼,並且請記住,內聯彙編程序在x64下是不允許的;它必須是完整的彙編模塊。