我正在尝试解析表达式树并编写了以下代码:
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();
}
代码的思想是解析表达式树并将有关节点的详细信息写入字符串变量输出。但是,当此变量写入页面时(使用Output()
方法),我发现它是空的。
当我使用调试器逐步执行代码时,我发现当代码第一次执行HandleParameterExpression()
时输出正确设置为'x',但是一旦控件从{{1}返回}回到HandleParameterExpression()
中的开关块,该变量再次神秘地为空。
由于字符串是引用类型,我应该只是能够在方法之间传递引用,并且应该保留对方法所做的值的更改,对吧?在C#中是否存在一些我不知道的参数传递的微妙之处?
答案 0 :(得分:8)
你永远不会在字符串中更改数据,因为它是不可变的。
每次有:
output += something;
那是说:
output = output + something;
“output + something”的值实际上是调用String.Concat(output, something)
的结果 - 即对新字符串的引用。因此,您的代码正在更改变量 output
的值以引用新字符串。现有字符串中的数据保持不变。
更改参数的值不会更改调用者中的相应值,除非参数通过引用传递(使用ref
或out
)。有关详细信息,请参阅我的article on parameter passing。注意通过值传递引用和通过引用传递变量之间的区别。
我建议您更改代码以改为使用StringBuilder
。
答案 1 :(得分:6)
您需要传入您想通过引用实际更改的任何变量。因此,在您的示例中,您需要这样做:
private void HandleOrElseExpression(Expression expression, ref string output)
然后当你调用这个函数时,你会这样做:
HandleOrElseExpression(expression, ref output)
答案 2 :(得分:3)
字符串是不可变的,因此通过为output
分配另一个值,您不会更改output
,而是创建新的字符串变量。
您可能希望将output
参数声明为ref
。
答案 3 :(得分:1)
您希望使用out
参数:
示例:将private void HandleExpression(Expression expression, string output)
更改为private void HandleExpression(Expression expression, out string output)
,并将HandleExpression(expression.Body, output);
替换为HandleExpression(expression.Body, out output);
然后在方法中写入output
将影响传递给函数的参数。