【问题标题】:Convert a function call to a Expression C#将函数调用转换为表达式 C#
【发布时间】:2016-09-27 11:49:01
【问题描述】:

我有以下函数,我想在其中遍历函数参数...

    private static void TestExpression(Expression expr)
    {            
        MethodCallExpression methodCall = expr as MethodCallExpression;
        if(methodCall == null)
            throw new ArgumentException("not a function call");

        ReadOnlyCollection<Expression> args = methodCall.Arguments;
        ParameterInfo[] param = methodCall.Method.GetParameters();
        param.ToList().ForEach(p => Console.WriteLine(p.Name));
    }

只是为了举例,我还有一个虚拟函数......

    static int SomeFunc(int a, int b)
    {
        return 0;
    }

问题是我不知道怎么把函数调用转换成Expression,也就是不知道怎么进行下面的调用

TestExpression(/*Something here converting SomeFunc(20, 30) to a Expression*/)

我想提一下,我对其他遍历参数的方法不感兴趣。我用 lambda 表达式尝试了多种变体,但没有成功......

【问题讨论】:

  • 我忘了说使用的是.Net 3.5

标签: c# .net-3.5 expression


【解决方案1】:

要使其适用于您当前的实现,您需要显式创建一个表达式并从中提取一个主体。代码如下:

TestExpression(((Expression<Func<int>>)(() => SomeFunc(1, 2))).Body);

但它的可读性不是很好。

编辑: 需要更多信息(例如特定用例)来尝试更改代码以提高可读性。

编辑: 为了提高可读性,您可以使用以下内容:

private static void TestExpression<T>(Expression<Func<T>> expr)
{
    TestExpression(expr.Body);
}

这将允许您像这样调用方法:

TestExpression(() => SomeFunc(1, 2));

当然,您仍然需要为参数提供默认值。要克服这个问题,您需要稍微更改TestExpression 重载,但在大多数情况下类型推断将不起作用。如果需要,您可以自行探索。

【讨论】:

  • 我已经尝试过这个版本,但它最终会抛出 ArgumentException,这意味着它不是有效的 MethodCallExpression。用例是我想创建一个测试函数(用于单元测试),它接受一个函数(或委托),通过它的参数并测试它是否抛出 ArgumentNullException 如果它们为空。这是避免繁琐和重复测试的自动化。我在网上找到了一些示例,但它们不完整或不起作用。另外,我很生气,我不能用这种方法做到这一点,想知道怎么做。
  • 我在本地测试了这个。你在链的末端看到.Body 吗?事实上,没有它,它就行不通,因为表达式类型将是Expression&lt;Func&lt;int&gt;&gt;,它派生自LambdaExpression,因此.Body 来提取实际的表达式。对于您的情况,我将引入另一层方法调用以使其更具可读性。请参阅我编辑的答案。
  • 谢谢,成功了。在您的解决方案的第一次测试中,我忘记注释掉隐藏在许多 cmets 中的 TestExpression 调用版本。所以我实际上从我的版本中得到了 ArgumentException。 …… cmets 看不到森林。再次感谢。
猜你喜欢
  • 2021-07-30
  • 1970-01-01
  • 2012-07-24
  • 2019-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多