2010-08-20 68 views
1

我正在使用Reflection.Emit构建数学表达式分析器(例如2+2)。一个类采用中缀表达式(例如2+2),将其转换为后缀表达式(例如2 2 +),然后另一个类将该后缀表达式编译为IL并创建一个DynamicMethod。从那里,可以评估表达式,就好像它是在编译时创建的一样,具有相似的速度。使用Reflection调用使用MethodInfo实例的方法。使用Reflection.Emit

该编译器也支持隐式乘法,所以像x(2 + 2)目前计算为x * (2 + 2)

,我试图实现用户自定义函数(例如f(x))。当我试图区分隐式乘法(如上所示)和用户定义的函数时,会出现问题。例如,如果用户输入x(5),我如何知道他们是否要将x乘以5,或者调用x函数的参数为​​5

为了解决这个问题,在前面的例子中,编译器在IL流中插入if语句。它调用一个函数来确定函数是否以x的标识符定义。如果有的话,它会通过out变量和本地值将一个MethodInfo实例插入堆栈。

我的实际问题是,是否有可能执行一个方法使用堆栈上的MethodInfo实例在编译过程中等价于调用IlGenerator.Emit(OpCodes.Call, MethodInfo)

谢谢。

+0

设计建议:使乘法明确,或具有不同的函数调用语法。含糊不清的语法导致错误/难以识别用户错误。你知道标准的算术符号很糟糕,或者你不会转换为后缀,这是其中一个原因:) – 2010-08-20 03:27:57

回答

1

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

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

+0

非常感谢!虽然我没有在这里使用确切的解决方案,但却让我有一种不同的处理方式。 – mgbowen 2010-08-20 04:16:14

+0

@nasufara:请考虑解释您在单独的答案中找到的解决方案,以便其他人可以从中受益。 – Timwi 2010-08-20 07:39:54

相关问题