使用表达式树在c#中动态调用方法

4
我正在编写一个小型的表达式解析器,希望能够包含方法调用。语法应该像这样:functionName('stringValue',intValue)。
然后,表达式解析器需要查找具有正确签名(在本例中为字符串、整数)的静态函数“functionName”。
解析表达式没有问题,但我遇到了调用正确方法的问题。
到目前为止,我想到的方法是使用简单的Expression.Call:
Expression.Call(typeof(MyContext).GetMethod(functionName), parameterExpressions)

这个方法很简洁,后续可以编译成可调用的函数。但是,当有多个不同的重载、默认参数、params关键字等情况出现时,情况就变得复杂了。我不想重新实现整个C#的重载解析逻辑,想到使用DLR来帮助我。
使用dynamic关键字,我可以这样写:
dynamic myC = MyContext;
return myC.functionName(param1, param2);

DLR会找出要调用哪个函数重载。

问题是,我如何通过编程实现这一点?

到目前为止,我还没有成功使用

Expression.Dynamic(..)

你知道参数的类型吗? - Moby Disk
2个回答

2

GetMethod有一个重载,只要你知道类型,它就会为你解决重载冲突。同样地,Expression.Call()也有一个重载,它接受方法名和类型。

// Assuming you have parameter expressions with known types...
string functionName = "functionName";
ParameterExpression param1 = Expression.Parameter(typeof(string), "stringValue");
ParameterExpression param2 = Expression.Parameter(typeof(int), "intValue");
var parameterExpressions = new ParameterExpression[] { param1, param2};

// Extract the types...
Type[] parameterTypes = parameterExpressions.Select(p => p.Type).ToArray();

// This will do the overload resolution and give you the methodInfo
MethodInfo methodToCall = typeof(Robot).GetMethod(
    functionName,
    parameterTypes);
Expression e = Expression.Call(methodToCall, parameterExpressions);

我确实知道参数类型(在运行时),所以这听起来非常有前途!明天会尝试一下。 - trykyn
我只看了GetMethods的重载,从来没有看过GetMethod!谢谢你的帮助。 - trykyn
仔细看,这只处理重载,但在存在例如默认参数的情况下不提供重载解析。 - trykyn
Expression.Call 的重载版本需要使用类型数组,而不是对被调用方法进行重载决策-该数组严格用于指定泛型类型参数,如果该方法是泛型的话。如果要执行重载决策,则必须通过 GetMethod 进行操作(如果需要自定义操作方式,则可以使用自定义绑定程序)。然而,这并不能保证与 C# 重载决策规则完全匹配,因为默认绑定程序是与语言无关的。 - Pavel Minaev
@PavelMinaev 哇,好的,谢谢告知。我已经相应地更新了代码示例。 - Moby Disk

0

我的解决方案是:

  1. 解析原始输入(脚本)字符串
  2. 词法分析和映射(将函数映射到函数,变量映射到字典)
  3. 执行。

如果您可以解析出指令作为可标记化的字符串,则可以根据这些“字符串”执行非常特定的功能。

我刚刚发布了一个视频播放列表,可能值得检查一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接