Как получить исполняемый объект для стекового кадра?
При использовании отражения можно получить стек вызовов (кроме того, что это может быть грубое приближение из-за оптимизации JIT) с использованием System.Diagnostics.StackTrace и исследовать содержащиеся в нем объекты StackFrame.
Как я могу получить ссылку на объект (этот указатель), на котором выполняется метод в кадре стека?
Я знаю, что могу получить MethodBase, вызвав GetMethod() в объекте фрейма стека, но то, что я ищу, - это что-то вроде линий GetObject() (которое естественно возвращает null, если метод статичен), Кажется, что объект фрейма стека может быть запрошен только для статически определенной информации, такой как информация о методе, исходный файл и т.д.
Отладчик VS знает (хотя он, вероятно, использует другой метод получения трассировки стека вызовов), так как можно дважды щелкнуть любой стек стека в окне стека вызовов и посмотреть значения локалей и полей классов.
EDIT:
Чтобы уточнить: мне нужен объект экземпляр, на который был вызван метод. I.e: Если метод Foo() вызывается в экземпляре объекта где-то в стеке вызовов, и он каскадирует к методу, который я выполняю трассировку стека, я бы хотел получить ссылку на A, откуда выполняю трассировку стека. (Не объявляющий тип базы методов)
Ответы
Ответ 1
Я уверен, что это невозможно. Вот почему:
-
Это может нарушить безопасность типов, так как любой может найти кадр, получить объект независимо от того, какой AppDomain\Thread они выполняют или имеют ли они разрешение.
-
Идентификатор 'this
' (С#) - это просто аргумент метода экземпляра (первый), поэтому на самом деле нет никакой разницы между статическими методами и методами экземпляра, компилятор делает свою магию для передайте правильный this
метод экземпляра, что, конечно же, означает, что вам нужно иметь доступ ко всем аргументам метода для получения объекта this
. (который StackFrame
не поддерживает)
Возможно, с помощью кода unsafe
можно получить указатель первого аргумента на метод экземпляра и затем применить его к правильному типу, но я не знаю, как это сделать, просто идея.
Кстати, вы можете представить методы экземпляра после компиляции, чтобы быть похожими на методы расширения С# 3.0, они получают указатель this
в качестве своего первого аргумента.
Ответ 2
Можно получить ссылку на объект thiscall
, но не только на .NET-код. Необходимо задействовать собственный код. Даже с использованием динамических классов и пространства имен System.Relection.Emit.NET не имеет инструментов для доступа к другим методам оценки и аргументов.
С другой стороны, если вы разбираете свой метод .NET, вы можете видеть, что эта ссылка вообще не передается в физическом стеке. thiscall
ссылка сохраняется в регистре ECX
(RCX
для x64). Таким образом, можно подняться на стек от вашего метода до метода, из которого вы хотите получить объект thiscall
. И затем найдите внутри этого метода машинные коды для инструкции, которые сохраняют регистр ECX (RCX) в стеке, и получите от этого относительного адреса инструкции, где эта ссылка лежит.
Конечно, метод альпинизма сильно отличается в приложениях x32 и x64. Для создания такой функции вы должны использовать не только С#, но и код сборки, и имейте в виду, что встроенный ассемблер не разрешен в x64; он должен быть полным модулем ассемблера.
Ответ 3
Я не уверен, что полностью понимаю, чего вы хотите, но если вы хотите узнать тип, в котором объявлен метод для определенного стекового фрейма, я думаю, что этот код возвращает это:
StackTrace trace = new StackTrace();
Type methodOwner = trace.GetFrame(0).GetMethod().DeclaringType;
Конечно, вам необходимо передать индекс для интересующего фрейма (например, я использую 0).