Почему мы не можем определить переменную внутри оператора if? - PullRequest
43 голосов
/ 02 июля 2011

Возможно, на этот вопрос уже был дан ответ, но слово 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 примера оператора это не так.

Так в чем причина, по которой нам не разрешено это делать?

Ответы [ 5 ]

37 голосов
/ 03 июля 2011

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

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

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

StringBuilder sb = new StringBuilder("test")

По сути, вы делаете то же самое, что и:

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

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

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

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

В точности эквивалентно:

void F() {
   int x; x = 1;
   int y;
   int z; z = x * 2;
}
17 голосов
/ 20 июля 2018

Попробуйте C # 7's Pattern Matching .

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

if (new StringBuilder("test") is var sb && sb != null) {
    Console.WriteLine(sb);
}
9 голосов
/ 03 июля 2011

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

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

StringBuilder sb; // statement

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

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

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

Теперь перейдем к вашему условному заявлению. Синтаксис использования оператора not-equals:

expression != expression

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

3 голосов
/ 05 марта 2018

Вместо:

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.Затем условие цикла оценивается как ложное, и следующий оператор продолжается после выполнения закрывающей скобки.Точно так же, как первоначально предполагалось ваше заявление.

0 голосов
/ 03 июля 2011

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

StringBuilder sb = new StringBuilder("test");

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

...