Почему эта ошибка компиляции - PullRequest
9 голосов
/ 11 января 2012

Почему, если я пишу

void Main()
{
      string value = @"C:\";
      if (!string.IsNullOrEmpty(value))  { 
            string sDirectory = Path.GetDirectoryName(value);
      }

}

, он компилируется.

А если я пишу

void Main()
{
      string value = @"C:\";
      if (!string.IsNullOrEmpty(value))
        string sDirectory = Path.GetDirectoryName(value);


}

Это не так?

Ясно, что с чисто функциональной точки зрения объявление переменной в примере second бесполезно, но почему оно волшебным образом становится полезным в first пример, так?

Код IL, полученный в обоих примерах, точно одинаков.

IL_0000:  ldstr       "C:\"
IL_0005:  stloc.0     
IL_0006:  ldloc.0     
IL_0007:  call        System.String.IsNullOrEmpty
IL_000C:  brtrue.s    IL_0015
IL_000E:  ldloc.0     
IL_000F:  call        System.IO.Path.GetDirectoryName

РЕДАКТИРОВАТЬ:

Забыл упомянуть, что для получения кода IL для второго случая (так что дело, которое не компилируется), достаточно компилировать без string sDirectory =

Ответы [ 5 ]

20 голосов
/ 11 января 2012

Производство для оператора if приведено в разделе 8.7.1 спецификации C # и выглядит так:

if-statement:
    if   ( boolean-expression )   embedded-statement
    if   ( boolean-expression )   embedded-statement   else   embedded-statement

В начале раздела 8 спецификации C # явно говорится о производстве внедренного оператора после предоставления спецификации для него:

embedded-statement:
   block
   empty-statement
   expression-statement
   selection-statement
   iteration-statement
   jump-statement
   try-statement
   checked-statement
   unchecked-statement
   lock-statement
   using-statement 
   yield-statement

Нетерминал встроенного оператора используется для операторов, которые появляются внутри других операторов. Использование встроенного оператора, а не оператора, исключает использование операторов объявления и помеченных операторов в этих контекстах. Пример

void F(bool b) {
     if (b)
         int i = 44;
} 

приводит к ошибке времени компиляции, поскольку для оператора if требуется встроенный оператор, а не оператор для его ветви if. Если бы этот код был разрешен, тогда была бы объявлена ​​переменная i, но она никогда не могла бы использоваться. Однако обратите внимание, что, поместив объявление i в блок, пример действителен.

Обратите внимание, что присваивание считается как выражение-выражение - но объявление локальной переменной - нет. (Это оператор декларации , как в разделе 8.5.)

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

6 голосов
/ 11 января 2012

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

if (!string.IsNullOrEmpty(value))
    string sDirectory;
    sDirectory = Path.GetDirectoryName(value);

Вы можете видеть, что это не скомпилируется!

5 голосов
/ 11 января 2012

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

1 голос
/ 11 января 2012

Я не уверен в C #, но это относится и к другим языкам: потому что {} открыть блок и, следовательно, новую область видимости. Если вы их опускаете, то переменная объявляется в области действия Main и поэтому будет объявлена ​​только некоторое время, поэтому компилятор не будет знать, существует ли sDirectory или нет.

1 голос
/ 11 января 2012
string value = @"C:\";
if (!string.IsNullOrEmpty(value))
string sDirectory = Path.GetDirectoryName(value);

Второе утверждение - это то, что считается встроенным утверждением ... если вы хотите использовать sDirectory в рамках так называемого «блока кода», оберните вокруг него {}.встроенные утверждения, подобные тому, что вы пытаетесь сделать, по моему мнению, делают для плохой читаемости

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