3

I would like to create a function that converts a "C# function call" to a string. For example: In my C# Project there is a public function, that can be called like this:

myTestClass.myTestFunction();

It's a function without arguments and returnvalue. Now I would like to implement another function that accepts a C# "Expression" as argument and converts the "Expression" to a string:

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

myString should contain now "myTestClass.myTestFunction();" It is important that the complete function call including the class name is inside the string.

Any ideas how to solve this?

3
  • you might want to wait for c#6 with the nameof() function Commented Jan 16, 2015 at 18:43
  • I don't think there is a simple solution using the BCL,but there are some third party libraries that support printing expressions using C# syntax. Commented Jan 16, 2015 at 18:47
  • Search for "reflection" and "member expressions." This type of question has been answered here before. Commented Jan 16, 2015 at 18:47

3 Answers 3

4

For this case you can simply write

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

The general case is more complicated; however, this gives you an idea of where to start.


A more elaborate version prints parameters passed as constant expressions:

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();
}

It can cope with this expression:

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

However, since the parameters can be any valid expressions, it quickly becomes complicated to include other cases. And then there are out and ref parameters and optional parameters.

Sign up to request clarification or add additional context in comments.

1 Comment

@AT_VI_MaP, you mark a solution by clicking the checkmark to the left of the answer.
0

Just call ToString on the method's body.

string myString = expr.Body.ToString();

3 Comments

That prints a string representation of the expression, but the output is not a proper C# expression. Not sure if that's acceptable to the OP.
@CodesInChaos Where does he say that the output should be a C# expression? For the expression given he said that the output should be myTestClass.myTestFunction();. This creates that result for input of that format.
hmm, just checked. It doesn't include the class name for static methods.
0

what you're trying to get is an action

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);

because you're accessing myTestClass via a closure you need to realize that you're accessing it via a Member Expression so the body is a Method call. we get the method name from that, then we get the expression representing the object that we're calling the method on, we cast that to a member expression because that's what it is in this case and we get the name from the member on that member expression.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.