Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: String parameter being mysteriously reset to empty - please help!

I'm experimenting with parsing expression trees and have written the following code:

private void TestExpressionTree()
  {
    Expression<Func<int, bool>> expression = x => x == 1 || x == 2;
    string output = String.Empty;
    HandleExpression(expression.Body, output);
    Output("Output", output);
  }

  private void HandleExpression(Expression expression, string output)
  {
    switch (expression.NodeType)
    {
      case ExpressionType.Conditional:
        HandleConditionalExpression(expression, output);
        break;
      case ExpressionType.OrElse:
        HandleOrElseExpression(expression, output);
        break;
      case ExpressionType.Equal:
        HandleEqualExpression(expression, output);
        break;
      case ExpressionType.Parameter:
        HandleParameterExpression(expression, output);
        break;
      case ExpressionType.Constant:
        HandleConstantExpression(expression, output);
        break;
    }
  }

  private void HandleConditionalExpression(Expression expression, string output)
  {
    ConditionalExpression conditionalExpression = (ConditionalExpression) expression;
    HandleExpression(conditionalExpression.Test, output);
  }

  private void HandleOrElseExpression(Expression expression, string output)
  {
    BinaryExpression binaryExpression = (BinaryExpression)expression;
    HandleExpression(binaryExpression.Left, output);
    output += "||";
    HandleExpression(binaryExpression.Right, output);
  }

  private void HandleEqualExpression(Expression expression, string output)
  {
    BinaryExpression binaryExpression = (BinaryExpression)expression;
    HandleExpression(binaryExpression.Left, output);
    output += "=";
    HandleExpression(binaryExpression.Right, output);
  }

  private void HandleParameterExpression(Expression expression, string output)
  {
    ParameterExpression parameterExpression = (ParameterExpression)expression;
    output += parameterExpression.Name;
  }

  private void HandleConstantExpression(Expression expression, string output)
  {
    ConstantExpression constantExpression = (ConstantExpression)expression;
    output += constantExpression.Value.ToString();
  }

The idea of the code is to parse the expression tree and write details about the nodes into the string variable output. However, when this variable is written to the page (using the Output() method), I'm finding it's empty.

When I use the debugger to step through the code, I find that output is correctly set to 'x' when the code executes HandleParameterExpression() for the first time, but as soon as control returns from HandleParameterExpression() back to the switch block in HandleExpression(), the variable is mysteriously empty again.

Since strings are reference types, I should simply be able to pass the reference between the methods and changes to its value made by the methods should be retained, right? Is there some subtlety of parameter passing in C# that I'm not aware of?

like image 425
David Avatar asked Dec 02 '10 13:12

David


2 Answers

You're never changing the data within the string, because it's immutable.

Each time you have:

output += something;

that's saying:

output = output + something;

The value of "output + something" is actually the result of calling String.Concat(output, something) - i.e. a reference to a new string. So your code is changing the value of the variable output to refer to the new string. The data in the existing string remains unchanged.

Changing the value of a parameter won't change the corresponding value in the caller, unless the parameter is passed by reference (using ref or out). See my article on parameter passing for more details. Note the difference between passing a reference by value, and passing a variable by reference.

I suggest you change your code to use StringBuilder instead.

like image 79
Jon Skeet Avatar answered Oct 01 '22 11:10

Jon Skeet


You need to pass in ANY variable that you want to actually change by reference. So, in your example, you would need to do it this way:

private void HandleOrElseExpression(Expression expression, ref string output)

And then when you call the function, you would do it this way:

HandleOrElseExpression(expression, ref output)
like image 20
Charles Boyung Avatar answered Oct 01 '22 13:10

Charles Boyung