C #: параметр строки загадочным образом сбрасывается в пустой - пожалуйста, помогите! - PullRequest
5 голосов
/ 02 декабря 2010

Я экспериментирую с синтаксическим анализом деревьев выражений и написал следующий код:

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()), я обнаруживаю, что она пуста.

Когда я использую отладчик для пошагового выполнения кода, я нахожу, что вывод правильно установлен в 'x', когда код выполняет HandleParameterExpression() в первый раз, но как только управление возвращается из HandleParameterExpression() обратно в переключите блок в HandleExpression(), переменная снова загадочно пуста.

Поскольку строки являются ссылочными типами, я должен просто иметь возможность передавать ссылку между методами, и изменения в его значении, сделанные методами, должны быть сохранены, верно? Есть ли какая-то тонкость передачи параметров в C #, о которой я не знаю?

Ответы [ 4 ]

8 голосов
/ 02 декабря 2010

Вы никогда не меняете данные внутри строки, потому что она неизменна.

Каждый раз, когда у вас есть:

output += something;

, то есть:

output = output + something;

Значение «output + что-то» на самом деле является результатом вызова String.Concat(output, something) - то есть ссылки на новую строку.Таким образом, ваш код изменяет значение переменной output для ссылки на новую строку.Данные в существующей строке остаются без изменений.

Изменение значения параметра не приведет к изменению соответствующего значения в вызывающей программе, если только параметр не передан по ссылке (с использованием refили out).Смотрите мою статью о передаче параметров для более подробной информации.Обратите внимание на разницу между передачей ссылки по значению и передачей переменной по ссылке.

Я предлагаю вам изменить код для использования StringBuilder вместо.

6 голосов
/ 02 декабря 2010

Вам нужно передать ЛЮБУЮ переменную, которую вы хотите изменить по ссылке. Итак, в вашем примере вам нужно сделать это следующим образом:

private void HandleOrElseExpression(Expression expression, ref string output)

И затем, когда вы вызываете функцию, вы делаете это следующим образом:

HandleOrElseExpression(expression, ref output)
3 голосов
/ 02 декабря 2010

Строки являются неизменяемыми, поэтому, присваивая другое значение output, вы не изменяете output, а создаете новую строковую переменную.

Возможно, вы захотите объявить параметр output как ref.

1 голос
/ 02 декабря 2010

Похоже, вы хотите использовать out params:

Пример: изменить 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 в методе повлияетаргумент передан функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...