Dar*_*rio 7 .net c# scope dynamic-languages
即使可以在运行时编译C#代码,也不可能在当前范围中包含和运行生成的代码.相反,所有变量都必须作为显式参数传递.
与像Python这样的动态编程语言相比,人们永远无法真正复制完整的行为eval(如本例所示).
x = 42
print(eval("x + 1")) # Prints 43
Run Code Online (Sandbox Code Playgroud)
所以我的问题是(无论它是否真的有用;))是否可以通过使用反射来模拟.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
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,是否可以通过使用反射来模拟.NET中的动态范围.
反射使得其在所表达的项目的运行时操作的元数据的的组件.
局部变量不是在程序集的元数据中表示的项.
因此,你的问题的答案是"不".
(如何)是否可以可靠地访问调用方法的本地?
访问调用方法的本地的设备称为"调试器".所以你的问题的答案是"自己写一个调试器".
请注意,调试器无法可靠地访问具有代码优化的世界中的本地.本地可以被优化掉,抖动可以生成代码,这些代码对两个不同的本地使用相同的寄存器,在尾调用期间可以重复使用堆栈帧,等等.当然,您最好使用PDB文件告诉调试器与每个堆栈帧位置关联的名称是什么.
您的方法必须做的是将自定义调试器作为新进程启动,然后等待调试器向其发送消息.然后调试器将挂起原始进程的线程,查询堆栈帧,然后恢复进程的线程.然后它会向调试对象发送包含您发现的信息的消息.由于调试对象正处于等待状态等待消息,因此它将恢复其业务.
如果您想要的是一个进程内 "eval"功能,请考虑JScript.NET,这是一种专为此类设计的语言.
这是不可能的.在编译的.NET代码(中间语言)中,变量简单地表示为堆栈上的索引.例如,加载变量值的ldloc指令只接受一个unsigned int16值作为参数.对于在调试模式下编译的应用程序,可能有某种方法可以执行此操作(毕竟,在调试应用程序时,Visual Studio会这样做),但它通常无法正常工作.
在Phalanger(用于.NET的PHP编译器,我部分参与其中),这必须以某种方式解决,因为PHP语言具有eval(它不需要提供动态范围,但它需要按名称访问变量).因此,Phalanger检测函数是否包含任何使用,eval如果有,它将所有变量存储在中Dictionary<string, object>,然后传递给eval函数(以便它可以按名称读取变量).我担心这是唯一的方法......
| 归档时间: |
|
| 查看次数: |
472 次 |
| 最近记录: |