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?
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.
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)
Strings are immutable, so by assigning another value to output
, you are not changing output
, but creating a new string variable.
You might want to declare the output
parameter as ref
.
Looks like you want to use out
params:
Example: Change private void HandleExpression(Expression expression, string output)
to private void HandleExpression(Expression expression, out string output)
and replace HandleExpression(expression.Body, output);
with HandleExpression(expression.Body, out output);
Then writing to output
in the method will affect the argument passed to the function.
精彩评论