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