2009-05-20 10 views
11

Bei der Verwendung von Reflection ist es möglich, den Aufruf-Stack zu erhalten (abgesehen davon, dass es aufgrund von JIT-Optimierungen eine grobe Näherung sein kann), indem System.Diagnostics.StackTrace verwendet wird und die enthaltenen StackFrame-Objekte untersucht werden.Wie bekomme ich das ausführende Objekt für einen Stackframe?

Wie kann ich einen Verweis auf das Objekt (den this-Zeiger) erhalten, auf dem eine Methode in einem Stapelrahmen ausgeführt wird?

Ich weiß, dass ich die MethodBase abrufen kann, indem ich GetMethod() für das Stack-Frame-Objekt abrufe, aber was ich suche, ist etwas wie GetObject(), das natürlich Null zurückgibt, wenn die Methode statisch ist). Es scheint, als ob das Stack-Frame-Objekt nur nach statisch bestimmten Informationen wie Methodeninformationen, Originaldateien usw. abgefragt werden kann.

Der VS-Debugger weiß (obwohl er wahrscheinlich eine andere Methode zum Erhalt der Call-Stack-Trace verwendet) Doppelklicken Sie auf einen Stapelrahmen im Call-Stack-Fenster und sehen Sie sich die Werte der lokalen und Klassenfelder an.

EDIT: Zur Klarstellung: Ich möchte das Objekt Instanz, auf dem die Methode aufgerufen wurde. Id.e .: Wenn die Methode Foo() auf der Objektinstanz A irgendwo auf dem Aufrufstapel aufgerufen wird und auf die Methode, die ich die Stapelverfolgung verwende, kaskadiert, möchte ich einen Bezug auf A erhalten, von wo aus ich die Stapelverfolgung durchführe. (Nicht der deklarierende Typ der Methodenbasis)

Antwort

6

Ich bin mir ziemlich sicher, dass dies nicht möglich ist. Hier ist der Grund:

  1. Dies könnte Typsicherheit brechen, da jemand einen Rahmen Nachschlag kann, erhalten Sie das Objekt unabhängig davon, welche AppDomain \ Thema sie ausgeführt werden auf oder Erlaubnis sie haben.

  2. Die ‚this‘ (C#) -Kennung ist wirklich nur ein Argument für die Instanz-Methode (die ersten), so in Wirklichkeit gibt es keinen Unterschied zwischen statischen Methoden und Instanzmethoden, führt der Compiler seine Magie das Recht passieren this zu einer Instanzmethode, was natürlich bedeutet, dass Sie Zugriff auf alle Methodenargumente haben müssen, um das this Objekt zu erhalten. (Die StackFrame nicht unterstützt)

es möglich sein könnte unsafe Code unter Verwendung der Zeiger des ersten Arguments auf eine Instanz Methode zu bekommen und dann nach rechts Typ Gießen, aber ich habe keine Kenntnisse darüber, wie um das zu tun, nur eine Idee.

BTW können Sie sich vorstellen, Instanz-Methoden nach dem kompiliert werden wie C# 3.0-Erweiterung Methoden, erhalten sie die this Zeiger als ihr erstes Argument.

+0

Ich weiß, dass dieser Zeiger an die übergeben wird aufgerufene Methode auf dem Aufruf-Stack durch den Aufrufer, weshalb die nicht vorhandene GetObject() Null zurückgeben würde, wenn es eine statische Methode wäre, und eine Kopie des kanonischen "This" -Zeigers in einer Instanzmethode. Allerdings stimme ich Ihrem Argument Nr. 1 zu, mit der Ausnahme, dass der Zugriff auf das Objekt leicht eingeschränkt werden kann, indem die entsprechende Berechtigung vom Entwurf gefordert wird. –

+0

Das eigentliche Problem ist, dass ein StackFrame nur einige Metadaten über Ihren Code enthält, es ist keine Live-Version Ihres Codes. – Yona

+0

Wie ich befürchtet habe. Aber ich hoffte, dass es noch andere Klassen geben würde. –

-1

Ich bin mir nicht sicher, ob ich vollständig verstehe, was Sie wollen, aber wenn Sie den Typ wissen wollen, in dem die Methode für einen bestimmten Stack-Frame deklariert wird, denke ich diesen Code kehrt das:

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

Sie natürlich den Index für den Rahmen, die Sie interessiert sind (ich verwende 0 als Beispiel) passieren benötigen.

+2

Ich denke, er meint die Instanz, nicht der Typ. –

+0

Ja, "Objekt" bedeutet Instanz eines Typs;) –

+0

Ja, ich habe festgestellt, dass (es ist eigentlich ziemlich klar in Ihrer Frage; Ich war ein bisschen müde, denke ich ...) –

3

Es ist möglich, einen Verweis auf thiscall Objekt, aber nicht nur mit .NET-Code zu erhalten. Nativer Code muss beteiligt sein. Auch bei Verwendung dynamischer Klassen und des System.Relection.Emit-Namespaces verfügt .NET über keine Instrumente, um auf einen anderen Methodenauswertungsstapel und andere Argumente zuzugreifen.

Auf der anderen Seite, wenn Sie Ihre .NET-Methode disassemblieren, können Sie sehen, dass diese Referenz überhaupt nicht auf physischen Stapel weitergegeben wird. Thiscall Referenz wird stattdessen in ECX (RCX für x64) Register gespeichert. Es ist also möglich, auf dem Stapel von Ihrer Methode zu der Methode hochzusteigen, von der Sie thiscall Objekt erhalten möchten. Suchen Sie dann in den Maschinencodes dieser Methode nach Anweisungen, die das Register ECX (RCX) im Stapel speichern und von dieser Befehlsrelativadresse, wo diese Referenz liegt.

Natürlich ist die Methode des Kletterns stark unterschiedlich in x32 und x64 Anwendung. Um eine solche Funktion zu erzeugen, müssen Sie nicht nur C#, sondern Assemblercode verwenden, und beachten Sie, dass Inline-Assembler unter x64 nicht erlaubt ist; Es muss ein komplettes Assembler-Modul sein.

Verwandte Themen