Даже при том, что возможно скомпилировать код 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
}
Это невозможно. В скомпилированном коде .NET (промежуточный язык) переменные представлены просто как индексы на стеке. Например, инструкция ldloc
, которая загружает значение переменной, принимает в качестве параметра только значение unsigned int16
. Возможно, есть какой-то способ сделать это для приложений, скомпилированных в режиме отладки (в конце концов, при отладке приложения это делает Visual Studio), но в общем случае это не может работать.
В Phalanger (компилятор PHP для .NET, которым я частично занимаюсь) это нужно было как-то решить, потому что в языке PHP есть eval
(ему не нужно обеспечивать динамическую развертку, но ему нужно обращаться к переменным по имени). Итак, Phalanger определяет, содержит ли функция использование eval
, и если да, то сохраняет все переменные в Dictionary
, который затем передается функции eval
(чтобы она могла читать переменные по их имени). Боюсь, что это единственный способ сделать это...
Итак, мой вопрос заключается в том, можно ли имитировать динамическую область видимости в .NET с помощью отражения.
Отражение позволяет во время выполнения манипулировать элементами, которые выражены в метаданных сборки .
Локальные переменные не являются элементами, выраженными в метаданных сборки.
Следовательно, ответ на ваш вопрос - «нет».
(Как) можно надежно получить доступ к локальным переменным вызывающих методов?
Устройство, которое обращается к локальным переменным вызывающего метода, называется «отладчиком». Итак, ответ на ваш вопрос - «напишите себе отладчик».
Обратите внимание, что отладчики не надежно получают доступ к локальным в мире с оптимизацией кода. Локальные переменные можно оптимизировать, джиттер может генерировать код, который использует один и тот же регистр для двух разных локальных переменных, кадры стека можно повторно использовать во время хвостовых вызовов и т. Д. И, конечно же, вам лучше иметь файл PDB, который сообщает отладчику, какие имена связаны с каждым местоположением кадра стека.
Ваш метод должен будет запустить собственный отладчик как новый процесс, а затем ждать, пока отладчик отправит ему сообщение. Затем отладчик приостанавливает потоки исходного процесса, выполняет опрос кадров стека, а затем возобновляет потоки процесса. Затем он будет отправлять сообщения отлаживаемой программе, содержащие обнаруженную вами информацию. Поскольку отлаживаемый компонент находится в состоянии ожидания, ожидая сообщений, он возобновит свою работу.
Если вам нужна возможность внутрипроцессного "eval", рассмотрите JScript.NET, язык, который был разработан для такого рода вещей.