表达式的部分评估

Partial evaluation of expressions

我想将方法​​调用捕获为表达式,但事先以类型安全且 IDE 友好的方式评估其参数。

举下面的例子class:

class Test
{
    public string SomeMethod(int a, string b) { ... }
}

我现在想将对 SomeMethod 的调用传递给接收 Expression:

的函数
HandleMethodCall<Test>(test => test.SomeMethod("string".Length, 5.ToString()));

现在HandleMethodCall有签名

static void HandleMethodCall<T>(Expression<Func<T, object>> expr)

不幸的是,在这种情况下,传递给 HandleMethodCall 的表达式不仅包含 test.SomeMethod(),还包含参数的表达式树。

一种解决方法是将方法调用及其参数拆分为 HandleMethodCall 的不同参数,但这样做的代价是失去编译时类型安全和 IDE 对显示参数的支持名字。

有什么方法可以让编译器在将表达式的某些部分放入 Expression 对象之前对它们求值?

或者,是否可以手动调用方法参数的表达式树求值?

看起来不可能在编译时指定它,但是可以使用 Expression.Lambda<>(...).Compile()() 在运行时编译和计算表达式部分(参见 documentation)。

这导致以下实现(为简单起见没有错误检查):

public static void HandleMethodCall<T>(Expression<Func<T, object>> expr)
{
    // Extract method call
    var methodCall = (MethodCallExpression)expr.Body;

    // Run through expected arguments and evaluate the supplied ones
    var expectedArguments = methodCall.Method.GetParameters();
    for(int i = 0; i < expectedArguments.Length; ++i)
    {
        Console.Write(expectedArguments[i].Name + ": ");

        // Since we do not know the argument type in advance, we have to use Func<object>
        var argumentEvaluationExpression = Expression.Lambda<Func<object>>(Expression.Convert(methodCall.Arguments[i], typeof(object)));
        object argumentValue = argumentEvaluationExpression.Compile()();

        Console.WriteLine(argumentValue);
    }
}

调用这个函数
HandleMethodCall<Test>(test => test.SomeMethod("string".Length, "1" + " 2 " + (1 + 2).ToString()));

输出预期结果

a: 6
b: 1 2 3

但是,我不确定这是否真的适用于所有条件。此外,由于 Compile() 步骤,我预计这是

感谢@RyanWilson 的有用评论,让我找到了这个解决方案!