【问题标题】:Convert C# function call to a string将 C# 函数调用转换为字符串
【发布时间】:2015-01-16 18:41:45
【问题描述】:

我想创建一个将“C# 函数调用”转换为字符串的函数。 例如: 在我的 C# 项目中有一个公共函数,可以这样调用:

myTestClass.myTestFunction();

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

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

myString 现在应该包含“myTestClass.myTestFunction();” 包括类在内的完整函数调用很重要 名称在字符串内。

有什么办法解决这个问题吗?

【问题讨论】:

  • 你可能想用nameof()函数等待c#6
  • 我认为使用 BCL 没有简单的解决方案,但是有一些第三方库支持使用 C# 语法打印表达式。
  • 搜索“反射”和“成员表达式”。此类问题之前已在此处得到解答。

标签: c#


【解决方案1】:

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

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,您可以通过单击答案左侧的复选标记来标记解决方案。
【解决方案2】:

只需在方法的主体上调用ToString

string myString = expr.Body.ToString();

【讨论】:

  • 打印表达式的字符串表示,但输出不是正确的 C# 表达式。不确定 OP 是否可以接受。
  • @CodesInChaos 他在哪里说输出应该是 C# 表达式?对于给定的表达式,他说输出应该是myTestClass.myTestFunction();。这将为该格式的输入创建结果。
  • 嗯,刚刚检查过。它不包括静态方法的类名。
【解决方案3】:

你想要的是一个动作

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,您需要意识到您正在通过成员表达式访问它 所以主体是一个方法调用。我们从中获得方法名称,然后我们获得表示我们正在调用该方法的对象的表达式,我们将其转换为成员表达式,因为在这种情况下就是这样,我们从成员那里获得名称成员表达式。

【讨论】:

    猜你喜欢
    • 2014-03-28
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    • 2018-11-24
    • 1970-01-01
    相关资源
    最近更新 更多