将C#函数调用转换为字符串

3

我希望创建一个将"C#函数调用"转换为字符串的函数。 例如: 在我的C#项目中,有一个公共函数,可以通过以下方式调用:

myTestClass.myTestFunction();

这是一个没有参数和返回值的函数。 现在我想要实现另一个函数,该函数接受C#“表达式”作为参数,并将“表达式”转换为字符串:

Expression<Func<???>> expr = () => myTestClass.myTestFunction();
string myString="";
myString=convertExpressionToString(expr);

现在,myString应该包含"myTestClass.myTestFunction();"。完整的函数调用,包括类名,是字符串中很重要的一部分。

有什么解决办法吗?


你可能想要等待C#6的nameof()函数。 - DLeh
我认为使用BCL没有简单的解决方案,但是有一些第三方库支持使用C#语法打印表达式。 - CodesInChaos
搜索“反射”和“成员表达式”。这种类型的问题以前已经在这里回答过了。 - joelmdev
3个回答

4
对于这种情况,你可以简单地编写:

对于此情况,您可以简单编写:

private static string ConvertExpressionToString(LambdaExpression expr)
{
    var methodCallExpr = expr.Body as MethodCallExpression;
    if (methodCallExpr != null ) {
        return methodCallExpr.Method.DeclaringType.Name + "." +
            methodCallExpr.Method.Name + "();";
    }
}

一般情况比较复杂,但这给你一个开始的想法。


更详细的版本会打印作为常量表达式传递的参数:

private static string ConvertExpressionToString(LambdaExpression expr)
{
    var sb = new StringBuilder();
    var methodCallExpr = expr.Body as MethodCallExpression;
    sb.Append(methodCallExpr.Method.DeclaringType.Name)
        .Append(".")
        .Append(methodCallExpr.Method.Name)
        .Append("(");
    var arguments = methodCallExpr.Arguments;
    for (int i = 0; i < arguments.Count; i++) {
        if (i > 0) {
            sb.Append(", ");
        }
        var constExpr = arguments[i] as ConstantExpression;
        if (constExpr == null) {
            sb.Append("<expr>");
        } else {
            sb.Append(constExpr.ToString());
        }
    }
    sb.Append(");");
    return sb.ToString();
}

它可以处理这个表达式:

Expression<Action> expr = () => myTestClass.myTestFunction(5, "hello");

然而,由于参数可以是任何有效的表达式,因此包含其他情况很快变得复杂。还有 outref 参数以及可选参数。


非常感谢您,您的解决方案解决了我的问题! - AT_VI_MaP
@AT_VI_MaP,要将一个解决方案标记为已解决,只需点击答案左侧的复选标记。 - Dour High Arch

0

你想要的是一个动作

Expression<Action> expr = () => myTestClass.myTestFunction();
MethodCallExpression mbr = (MethodCallExpression)expr.Body;
String methodName = mbr.Method.Name;
Assert.AreEqual(methodName, "myTestFunction");
MemberExpression me = (MemberExpression) mbr.Object;
String memberName = me.Member.Name;
Assert.AreEqual(methodName, "myTestClass");
String finalName = string.Format("{0}.{1}()", memberName, methodName);
Assert.AreEqual("myTestClass.myTestFunction()", finalName);

因为你是通过闭包访问 myTestClass,所以你需要意识到你是通过成员表达式来访问它的。因此,函数体是一个方法调用。我们从中获取方法名,然后获取表示我们调用该方法的对象的表达式,我们将其转换为成员表达式,因为在这种情况下它就是成员表达式,并从该成员表达式的成员中获取名称。


0

只需在方法体上调用ToString即可。

string myString = expr.Body.ToString();

这会打印出表达式的字符串表示形式,但输出不是一个合适的C#表达式。不确定这是否符合OP的要求。 - CodesInChaos
@CodesInChaos他在哪说输出应该是C#表达式?对于给定的表达式,他说输出应该是myTestClass.myTestFunction();。这将为该格式的输入创建该结果。 - Servy
嗯,刚刚检查了一下。它没有包括静态方法的类名。 - CodesInChaos

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