Подтвердить что ты не робот

Почему мы не можем определить переменную внутри оператора if?

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

Пример не имеет смысла (выражение всегда верно), но оно иллюстрирует мой вопрос.

Почему этот код действителен:

StringBuilder sb;
if ((sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

Но этот код не является:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

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

Так почему же нам не разрешено это делать?

4b9b3361

Ответ 1

Это связано с тем, что раздел 8.5.1 спецификации языка С#. говорится:

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

Это в основном означает, что, когда вы делаете:

StringBuilder sb = new StringBuilder("test")

Фактически вы делаете то же самое, что:

StringBuilder sb; sb = new StringBuilder("test")

Как таковое, больше нет возвращаемого значения для вашей проверки против != null, поскольку присваивание не является одним выражением, а скорее выражением, которое является декларатором локальной переменной, состоящим из идентификатора, за которым следует выражение.

Спецификация языка дает этот пример, указав, что это:

void F() {
   int x = 1, y, z = x * 2;
}

В точности соответствует:

void F() {
   int x; x = 1;
   int y;
   int z; z = x * 2;
}

Ответ 2

Попробуйте С# 7 Pattern Matching.

Используя ваш пример:

if (new StringBuilder("test") is var sb && sb != null) {
    Console.WriteLine(sb);
}

Ответ 3

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

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

StringBuilder sb; // statement

sb = new StringBuilder("test") // expression

StringBuilder sb = new StringBuilder("test"); // statement

Обратите внимание, что только средняя часть является выражением.

Теперь мы перейдем к вашему условному утверждению. Синтаксис для использования оператора неравных равен

expression != expression

Итак, по обе стороны от != вам нужно что-то, что на самом деле имеет значение (это имеет смысл). Эрго, вы не можете иметь утверждений по обе стороны оператора. Вот почему одна версия вашего кода работает, а другая - нет.

Ответ 4

Вместо:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

Можно также написать:

for (StringBuilder sb = new StringBuilder("test"); sb != null; sb = null) {
    Console.WriteLine(sb);
}

Этот цикл for будет выполнен один раз, если ваша переменная не равна нулю. В конце цикла ваша временная переменная имеет значение null. Затем условие цикла оценивается как ложное, и следующий оператор продолжается после выполнения закрывающей скобки. Точно так же, как ваше первоначальное утверждение.

Ответ 5

Как и в комментарии Джеффа, для этого кода вывод равен нулю:

StringBuilder sb = new StringBuilder("test");

а для оператора if требуется значение.