Почему не может быть объявлено дублируемое имя переменной во вложенной локальной области?

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

static void Main()
{
  {
    int i;
  }
  int i;
}

Этот код не может скомпилироваться со следующей ошибкой:

Локальная переменная с именем "i" не может быть объявлена ​​в этой области, потому что она будет иметь другое значение для "i", которое уже используется в области "child", чтобы обозначить что-то еще

Ответ 1

Я не думаю, что какой-либо из ответов до сих пор получил ключевую строку из спецификации.

Из раздела 8.5.1:

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

(Подчеркните мой.)

Другими словами, область для "более поздней" переменной включает в себя часть блока перед объявлением, то есть включает в себя "внутренний" блок, содержащий "более раннюю" переменную.

Вы не можете ссылаться на более позднюю переменную в месте раньше своего объявления - но все еще в области.

Ответ 2

"Объем локальной или постоянной переменной продолжается до конца текущего блока. Вы не можете объявить другую локальную переменную с тем же именем в текущем блоке или в любых вложенных блоках". С# 3.0 в двух словах, http://www.amazon.com/3-0-Nutshell-Desktop-Reference-OReilly/dp/0596527578/

"Локальное пространство объявления переменной блока включает любые вложенные блоки. Таким образом, внутри вложенного блока невозможно объявить локальную переменную с тем же именем, что и локальная переменная в закрывающем блоке." Переменные области, MSDN, http://msdn.microsoft.com/en-us/library/aa691107%28v=vs.71%29.aspx

На стороне примечания это совершенно противоположно правилам JavaScript и F #.

Ответ 3

Из Спецификация языка С#:

Локальное пространство объявления переменной блока включает любые вложенные блоки. Таким образом, внутри вложенного блока невозможно объявить локальную переменную с тем же именем, что и локальная переменная в закрывающем блоке.

По существу, это не допускается, потому что в С# их области действительно перекрываются.

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

Ответ 4

Это было правило в С# из первой версии.

Разрешение совпадающих областей приведет только к путанице (программистов, а не компилятора).

Так что это было запрещено специально.

Ответ 5

Это не вопрос перекрытия областей. В С# простое имя не может означать больше одного объекта в блоке, где он был объявлен. В вашем примере имя i означает две разные вещи внутри одного и того же внешнего блока.

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

static void Main()
{
    int i;
    {
        int i;
    }
}

приведет к перекрытию областей различных переменных i, ваш пример является незаконным.

Ответ 6

Для С#, ISO 23270 (Информационные технологии - Программирование языки - С#), & sect; 10.3 (Декларации):

Каждый блок, блок switch, for-statement, foreach-statement или using-statement создает пространство декларации для локальных переменных и локальные константы, называемые пространством объявлений локальной переменной. Имена введенные в это пространство декларации через локальные переменные-объявления и локальные константы.

Если блок является телом экземпляра конструктор, метод или оператор, или get или set accessor для объявление индексатора, параметры, объявленные в таком объявлении, являются члены локального пространства декларации переменных блоков.

Если блок является тело общего метода, параметры типа, объявленные в таком объявлении являются членами локального пространства декларации переменных блоков.

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

[Примечание: Таким образом, внутри вложенного блока невозможно объявить локальный переменная или константа с тем же именем, что и локальная переменная или константа в закрытом блоке. Возможно, чтобы два вложенных блока содержали элементы с тем же именем, если ни один из блоков не содержит другого. end note]

Итак,

public void foobar()
{
  if ( foo() )
  {
     int i = 0 ;
     ...
  }

  if ( bar() )
  {
    int i = 0 ;
    ...
  }

  return ;
}

является законным, но

public void foobar()
{
  int i = 0 ;

  if ( foo() )
  {
     int i = 0 ;
     ...
  }

  ...

  return ;
}

не является законным. Лично я считаю, что это ограничение довольно раздражает. Я вижу, как выдает предупреждение компилятора о перекрытии областей, но ошибка компиляции? Слишком много ремней и подтяжек, ИМХО. Я мог видеть достоинство опции компилятора и/или прагмы, хотя (возможно, -pedantic/-practical, #pragma pedantic vs #pragma practical, B^)).

Ответ 7

Я просто скомпилировал это в GCC как C, так и С++. Я не получил сообщение об ошибке, поэтому он выглядит как синтаксис.

Ваш вопрос помечен как .net и c. Должно ли это быть помечено как С#? Этот язык может иметь разные правила, чем C.

Ответ 8

В C вам нужно поместить все объявления переменных в самом начале блока. Они должны поступать сразу после открытия { перед любыми другими инструкциями в этом блоке.

Итак, что вы можете сделать, чтобы скомпилировать это:

static void Main()
{
  {
    int i;
  }
  {
    int i;
  }
}

Ответ 9

Вот ваш ответ от Документация MSDN.NET:

... Локальное пространство объявления переменной блока включает любые вложенные блоки. Таким образом, внутри вложенного блока невозможно объявить локальную переменную с тем же именем, что и локальная переменная в закрывающем блоке.