Как получить доступ к местным жителям через трассировку стека?(Имитация динамического объема) - PullRequest
7 голосов
/ 14 февраля 2010

Фон

Несмотря на то, что можно компилировать код C # во время выполнения, невозможно включить и запустить сгенерированный код в текущей области. Вместо этого все переменные должны быть переданы как явные параметры.

По сравнению с динамическими языками программирования, такими как Python, невозможно полностью воспроизвести полное поведение eval (как в этом примере).

x = 42
print(eval("x + 1")) # Prints 43

Вопрос

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

Поскольку .NET предоставляет нам класс Diagnostics.StackTrace, который позволяет нам проверять вызывающие методы, этот вопрос сводится к следующему: (Как) можно ли надежно получить доступ к локальным объектам вызывающих методов

Предоставляет ли нам трассировка стека достаточную информацию для вычисления смещений памяти, или в любом случае такие вещи запрещены в управляемом коде?

Возможен ли такой код?

void Foo() {
   int x = 42;
   Console.WriteLine(Bar());
}

int Bar() {
   return (int)(DynamicScope.Resolve("x")); // Will access Foo's x = 42
}

Ответы [ 2 ]

8 голосов
/ 14 февраля 2010

Поэтому мой вопрос заключается в том, возможно ли имитировать динамическую область действия в .NET с помощью отражения.

Отражение позволяет во время выполнения манипулировать элементами, которые выражены в метаданных сборки .

Локальные переменные не являются элементами, выраженными в метаданных сборки.

Поэтому ответ на ваш вопрос «нет».

(Как) возможно ли надежно получить доступ к локальным объектам вызывающих методов?

Устройство, которое обращается к локальным объектам вызывающего метода, называется «отладчиком». Поэтому ответ на ваш вопрос «напишите себе отладчик».

Обратите внимание, что отладчики не надежно обращаются к локальным пользователям в мире с оптимизацией кода. Локальные данные могут быть оптимизированы, джиттер может генерировать код, который использует один и тот же регистр для двух разных локальных объектов, стековые кадры могут быть повторно использованы во время оконечных вызовов и т. И, конечно же, вам лучше иметь файл PDB, который сообщает отладчику имена, связанные с каждым местоположением стекового фрейма.

Ваш метод должен был бы запустить ваш собственный отладчик как новый процесс, а затем подождать, пока отладчик отправит ему сообщение. Затем отладчик приостанавливает потоки исходного процесса, выполняет опрос кадров стека и затем возобновляет потоки процесса. Затем он будет отправлять сообщения отладчику, которые содержат информацию, которую вы обнаружили. Поскольку отладчик находится в состоянии ожидания в ожидании сообщений, он затем возобновит свою работу.

Если вам нужна in-process «eval», рассмотрите JScript.NET, язык, который был разработан для такого рода вещей.

5 голосов
/ 14 февраля 2010

Это невозможно. В скомпилированном коде .NET (промежуточный язык) переменные представлены просто как индексы в стеке. Например, инструкция ldloc , которая загружает значение переменной, принимает в качестве параметра только значение unsigned int16. Может быть какой-то способ сделать это для приложений, скомпилированных в режиме отладки (в конце концов, при отладке приложения, Visual Studio делает это), но это не может работать вообще.

В Phalanger (PHP-компилятор для .NET, в котором я частично участвую) это нужно было как-то решить, потому что в языке PHP eval (не требуется динамическая область видимости * 1009). *, но для этого требуется доступ к переменным по имени). Таким образом, Phalanger обнаруживает, содержит ли функция какое-либо использование eval, и, если это так, сохраняет все переменные в Dictionary<string, object>, который затем передается в функцию eval (чтобы она могла читать переменные по их имени). Боюсь, это единственный способ сделать это ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...