Как получить исполняемый объект для стекового кадра? - PullRequest
11 голосов
/ 20 мая 2009

При использовании отражения можно получить стек вызовов (кроме того, это может быть грубое приближение из-за JIT-оптимизации) с использованием System.Diagnostics.StackTrace и исследовать содержащиеся объекты StackFrame.

Как получить ссылку на объект (указатель this), над которым выполняется метод в кадре стека?

Я знаю, что могу получить MethodBase, вызвав GetMethod () для объекта стекового фрейма, но я ищу что-то похожее на GetObject () (который, естественно, возвращает null, если метод статический) , Кажется, что объект стекового фрейма может запрашиваться только для статически определенной информации, такой как информация о методе, исходный файл и т. Д.

Отладчик VS знает (хотя он, вероятно, использует другой метод получения трассировки стека вызовов), так как можно дважды щелкнуть любой кадр стека в окне стека вызовов и посмотреть значения локальных и полей классов.

EDIT: Для уточнения: я хочу объект экземпляр , для которого был вызван метод. Т.е. если метод Foo () вызывается для экземпляра объекта A где-то в стеке вызовов, и он каскадно относится к методу, который я выполняю трассировку стека, я хотел бы получить ссылку на A, откуда я выполняю трассировку стека. (Не объявляемый тип базы метода)

Ответы [ 3 ]

6 голосов
/ 20 мая 2009

Я почти уверен, что это невозможно. И вот почему:

  1. Это может нарушить безопасность типов, так как любой может искать кадр, получать объект независимо от того, для какого AppDomain \ Thread он выполняется или какого разрешения он имеет.

  2. Идентификатор 'this' (C #) на самом деле является просто аргументом метода экземпляра (первого), поэтому на самом деле нет никакой разницы между статическими методами и методами экземпляра, компилятор делает свое волшебство передать право this методу экземпляра, что, конечно, означает, что вам потребуется доступ ко всем аргументам метода, чтобы получить объект this. (который StackFrame не поддерживает)

Возможно, с помощью кода unsafe можно получить указатель первого аргумента для метода экземпляра и затем привести его к нужному типу, но я не знаю, как это сделать, просто идея.

Кстати, вы можете представить методы экземпляра после компиляции как методы расширения C # 3.0, в качестве первого аргумента они получают указатель this.

3 голосов
/ 10 мая 2012

Можно получить ссылку на объект thiscall, но не только с помощью кода .NET. Родной код должен быть вовлечен. Даже с использованием динамических классов и пространства имен System.Relection.Emit .NET не имеет инструментов для доступа к стеку и аргументам оценки других методов.

С другой стороны, если вы разберете свой метод .NET, вы увидите, что эта ссылка вообще не передается в физический стек. Thiscall ссылка хранится в регистре ECX (RCX для x64). Таким образом, можно подниматься по стеку от вашего метода к методу, из которого вы хотите получить thiscall объект. А затем ищите внутри машинных кодов этого метода инструкции, которые сохраняют регистр ECX (RCX) в стеке, и получаете от относительного адреса этой инструкции, где находится эта ссылка.

Конечно, метод лазания сильно отличается в приложениях x32 и x64. Для создания такой функции вы должны использовать не только C #, но и ассемблерный код, и помнить, что встроенный ассемблер не разрешен в x64; это должен быть полный модуль ассемблера.

0 голосов
/ 20 мая 2009

Я не уверен, что полностью понимаю, что вы хотите, но если вы хотите знать тип, в котором объявлен метод для определенного стекового фрейма, я думаю, что этот код возвращает следующее:

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

Вам, конечно, нужно будет передать индекс для кадра, который вас интересует (я использую 0 в качестве примера).

...