【问题标题】:Call a method using a MethodInfo instance on the stack using Reflection.Emit使用 Reflection.Emit 在堆栈上使用 MethodInfo 实例调用方法
【发布时间】:2010-08-20 03:09:38
【问题描述】:

我正在使用 Reflection.Emit 构建一个数学表达式解析器(例如2+2)。一个类接受一个中缀表达式(例如2+2),将其转换为一个后缀表达式(例如2 2 +),然后另一个类将该后缀表达式编译成IL并创建一个DynamicMethod。从那里,可以像在编译时以相似的速度创建表达式一样评估表达式。

这个编译器还支持隐式乘法,所以像x(2 + 2) 这样的东西的计算结果是x * (2 + 2)

现在,我正在尝试实现用户定义的函数(例如f(x))。当我试图区分隐式乘法(如上所示)和用户定义的函数时,就会出现问题。例如,如果用户输入x(5),我如何知道他们是想将x 乘以5,还是使用5 的参数调用x 函数?

为了解决这个问题,在前一种情况下,编译器将if 语句插入到 IL 流中。它调用一个函数来确定该函数是否使用标识符x 定义。如果有,则通过out 变量和本地变量将MethodInfo 实例插入堆栈。

我的实际问题是,是否可以使用堆栈上的MethodInfo 实例执行一个方法,该方法与编译期间调用IlGenerator.Emit(OpCodes.Call, MethodInfo) 的速度相当?

谢谢。

【问题讨论】:

  • 一个设计建议:明确乘法,或者使用不同的函数调用语法。语法不明确会导致错误/难以识别用户错误。您知道标准算术符号很烂,或者您不会费心转换为后缀,这就是原因之一 :)

标签: c# cil reflection.emit methodinfo


【解决方案1】:

据我所知,允许您在堆栈上调用 MethodInfo 实例的唯一方法是在其上调用 Invoke 方法。我相信你已经意识到这种可能性,但你担心它可能太慢了。我建议您尝试一下并在压力下计时。您可能会发现它对于您的目的来说已经足够快了。

如果不是,那么您将不得不考虑如何重构您的设计,以免传递MethodInfo 实例。例如,您可以改为传递托管函数指针。这些是 ldftnldvirtftn 指令返回的内容。然后,您可以使用calli 指令来调用其中之一。您将需要使用SignatureHelper class 构造“呼叫站点描述”,calli 将其作为操作数。

【讨论】:

  • 非常感谢!虽然我在这里没有使用确切的解决方案,但它让我找到了一种不同的处理方式。
  • @nasufara:请考虑在单独的答案中解释您找到的解决方案,以便其他人可以从中受益。
猜你喜欢
  • 2012-09-20
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 2018-06-06
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多