Как получить доступ к местным жителям через отслеживание стека? (Имитирующий динамический контекст)

Фон

Даже при том, что возможно скомпилировать код 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
}
7
задан Dario 14 February 2010 в 15:47
поделиться

2 ответа

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

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

5
ответ дан 6 December 2019 в 19:36
поделиться

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

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

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

Следовательно, ответ на ваш вопрос - «нет».

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

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

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

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

Если вам нужна возможность внутрипроцессного "eval", рассмотрите JScript.NET, язык, который был разработан для такого рода вещей.

8
ответ дан 6 December 2019 в 19:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: