Перемещение условия оператора if в локальную переменную делает компилятор C # несчастным - PullRequest
7 голосов
/ 19 марта 2011

Не могли бы вы объяснить мне причину следующей ситуации.

Сегодня я написал код (изменяются только имена переменных):

private void Foo() 
{
    int firstInteger, secondInteger;
    const string firstStringValue = "1", secondStringValue = "2";

    if (!string.IsNullOrWhiteSpace(firstStringValue) && int.TryParse(firstStringValue, out firstInteger) &&
        !string.IsNullOrWhiteSpace(secondStringValue) && int.TryParse(secondStringValue, out secondInteger))
    {
        // Using firstInteger and secondInteger here
        firstInteger++;
        secondInteger++;
    }
}

Все было хорошо, пока я не решилпереместите условие if в переменную:

private void Foo()
{
    int firstInteger, secondInteger;
    const string firstStringValue = "1", secondStringValue = "2";

    bool firstIntegerAndSecondIntegerAreSpecified = 
        !string.IsNullOrWhiteSpace(firstStringValue) && int.TryParse(firstStringValue, out firstInteger) &&
        !string.IsNullOrWhiteSpace(secondStringValue) && int.TryParse(secondStringValue, out secondInteger);

    if (firstIntegerAndSecondIntegerAreSpecified)
    {
        // Use firstInteger and secondInteger here
        firstInteger++;
        secondInteger++;
    }
}

Теперь компилятор подчеркивает firstInteger и secondInteger переменнымиошибка "Локальная переменная не может быть инициализирована перед доступом".

Но почему?Единственное, что я сделал, это немного изменил код.И, как я понимаю, логика та же.

Ответы [ 6 ]

9 голосов
/ 19 марта 2011

Компилятор (точнее, спецификация) не обнаруживает взаимосвязи между значением firstIntegerAndSecondIntegerAreSpecified и вызовами int.TryParse.В первой форме это может сработать, что выполнение войдет в тело только в том случае, если оба вызова к int.TryParse выполнены, и, следовательно, оба имеют определенно назначенные значения (из-за параметров out).Поэтому в блоке if проблем не было.

Правила определенного присваивания не охватывают идею о том, что firstIntegerAndSecondIntegerAreSpecified будет истинным, только если были выполнены оба вызова, поэтому в телеif блок, переменные по-прежнему точно не назначены, следовательно ошибка.

6 голосов
/ 19 марта 2011

Компилятор не настолько умен, чтобы понять, что истинное значение в логической переменной гарантирует, что значения в целом числе установлены.Компилятор отслеживает только пути выполнения, а не допустимые значения.

В первом случае компилятор знает, что невозможно ввести оператор if без вызовов TryParse, устанавливающих переменные.Во втором случае оператор if отделен от вызовов TryParse, поэтому компилятору придется отслеживать значение переменной, чтобы выяснить отношение.

3 голосов
/ 19 марта 2011

В первом случае компилятор может посмотреть на условие if и знать , что тело не может выполнить, если обе переменные не имеют значений (TryParse всегда устанавливает параметр out, даже если он не работает).

Когда вы реорганизуете это условие в переменную, компилятор должен будет отследить эту локальную переменную, чтобы убедиться, что она не может быть записана вот того, когда это назначено, когда это используется в качестве условия.Поскольку компилятор не настолько умен, он не может быть уверен, что ваши переменные инициализированы («точно назначены»), поэтому он выдает ошибку.

1 голос
/ 19 марта 2011

Оператор if может быть введен, только если оба выражения выполнены, но bool может быть назначено преждевременно из-за короткого замыкания - если первая строка не может быть проанализирована, компилятор пропускает синтаксический анализ второй строки потому что независимо от результата значение bool должно быть ложным.

0 голосов
/ 19 марта 2011

Добавление к ответу Джона -

Может быть проще обрабатывать оба целых числа отдельно. И нет необходимости проверять NullOrWhiteSpace.

int.TryParse(firstStringValue, out firstInteger)
    firstInteger++;

int.TryParse(secondStringValue, out secondInteger)
    secondInteger++;

Вы даже можете извлечь этот фрагмент отдельным методом

0 голосов
/ 19 марта 2011

Компилятор иногда выдает эту ошибку. Конечно, если вы будете следовать логике вашего кода, вы увидите, что переменные всегда инициализируются перед использованием. Но компилятор не запускает логику, он действует только в соответствии с некоторыми основными правилами. И именно поэтому он часто выдает эту ошибку, даже если на самом деле в логике нет ошибки.

Решение простое: просто инициализируйте все переменные при их объявлении.

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