Я довольно давно использую C #, но так и не понял следующего:
public static void Main()
{
for (int i = 0; i < 5; i++)
{
}
int i = 4; //cannot declare as 'i' is declared in child scope
int A = i; //cannot assign as 'i' does not exist in this context
}
Так почему я не могу использовать значение 'i' вне блока for, если оно не позволяет мне объявлять переменную с этим именем?
Я думал, что переменная итератора, используемая циклом for, действительна только в своей области видимости.
int i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
Ответы:
Причина, по которой вам не разрешено определять переменную с тем же именем как в цикле for, так и вне цикла for, заключается в том, что переменные во внешней области действительны во внутренней области. Это означает, что в цикле for будет две переменные «i», если это будет разрешено.
Смотрите: Области MSDN
В частности:
и
А также: объявления локальных переменных (раздел 8.5.1 спецификации C #)
В частности:
(Акцент мой.)
Это означает, что объем
i
внутри вашего цикла for является циклом for. В то время как областьi
вне вашего цикла for - это весь основной метод плюс цикл for. Это означает, что у вас будет два вхожденияi
внутри цикла, что недопустимо в соответствии с вышеизложенным.Причина, по которой вам не разрешено делать,
int A = i;
заключается в том, чтоint i
эта функция предназначена только для использования внутриfor
цикла. Таким образом, он больше не доступен внеfor
цикла.Как вы можете видеть, обе эти проблемы являются результатом определения области; первая проблема (
int i = 4;
) приведет к двумi
переменным в пределахfor
цикла. Принимая во внимание,int A = i;
что приведет к доступу к переменной, которая выходит за рамки.Вместо этого вы могли бы объявить
i
область действия всего метода, а затем использовать ее как в методе, так и в области видимости цикла. Это позволит избежать нарушения любого из правил.РЕДАКТИРОВАТЬ :
Конечно, можно изменить компилятор C #, чтобы этот код компилировался вполне корректно. Ведь это действительно так:
Но действительно ли было бы полезно для удобства чтения и поддержки вашего кода иметь возможность писать такой код, как:
Подумайте о возможной ошибке здесь, последняя
i
распечатывает 0 или 4? Это очень маленький пример, за которым довольно легко следить и отслеживать, но он определенно намного менее удобен в обслуживании и читаем, чем объявление внешнегоi
под другим именем.NB:
Пожалуйста, обратите внимание, что области видимости C # отличаются от областей видимости C ++ . В C ++ переменные находятся только в области видимости от того, где они объявлены, до конца блока. Что сделало бы ваш код допустимой конструкцией в C ++.
источник
i
переменной должна быть ошибка ; это кажется мне более очевидным.i
определение было перемещено до цикла for, внутреннееi
определение будет помечено как недопустимое.Ответ Дж. Коммера правильный: вкратце, недопустимо, чтобы локальная переменная была объявлена в пространстве объявления локальной переменной, которое перекрывает другое пространство объявления локальной переменной , имеющее локальную переменную с тем же именем.
Здесь также нарушается дополнительное правило C #. Дополнительное правило заключается в том, что недопустимо использовать простое имя для ссылки на две разные сущности в двух разных перекрывающихся пространствах объявления локальных переменных. Так что не только ваш пример незаконен, но и незаконен:
Потому что теперь простое имя «x» используется внутри пространства объявления локальной переменной «y» для обозначения двух разных вещей - «this.x» и локального «x».
См. Http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ для более подробного анализа этих проблем.
источник
int y = this.x;
this.x
это не простое имя .Существует способ объявления и использования
i
внутри метода после цикла:Вы можете сделать это в Java (это может происходить из C, я не уверен). Конечно, это немного беспорядочно из-за имени переменной.
источник
Если бы вы объявили ,
i
прежде чем вашfor
цикл, вы думаете , он должен оставаться действительным , чтобы объявить его внутри цикла?Нет, потому что тогда сфера действия двух будет перекрываться.
Что касается неспособности сделать
int A=i;
, это просто потому, чтоi
существует только вfor
цикле, как и должно быть.источник
В дополнение к ответу Дж. Коммера (+1 к слову). В стандарте для NET-области есть следующее:
Таким образом, int i, помеченный внутри заголовка цикла for, будет в области видимости только во время блока цикла for, НО его время жизни длится до завершения
Main()
кода.источник
Самый простой способ подумать об этом - переместить внешнюю декларацию I над циклом. Это должно стать очевидным тогда.
В любом случае это один и тот же прицел, поэтому это невозможно.
источник
Кроме того, правила C # часто не нужны с точки зрения строгого программирования, но нужны для того, чтобы ваш код был чистым и читаемым.
например, они могли бы сделать это так, чтобы, если вы определили его после цикла, все было в порядке, однако тот, кто читает ваш код и пропустил строку определения, может подумать, что это связано с переменной цикла.
источник
Ответ Коммера технически верен. Позвольте мне перефразировать это с яркой метафорой слепого экрана.
Между блоком for и окружающим внешним блоком имеется односторонний слепой экран, так что код внутри блока for может видеть внешний код, но код во внешнем блоке не может видеть код внутри.
Поскольку внешний код не может видеть внутри, он не может использовать ничего, объявленного внутри. Но поскольку код в блоке for может видеть как внутри, так и снаружи, переменная, объявленная в обоих местах, не может использоваться однозначно по имени.
Так что либо ты этого не видишь, либо ты C #!
источник
Посмотрите на это так же, как если бы вы могли объявить
int
вusing
блоке:Однако, поскольку
int
не реализуетIDisposable
, это не может быть сделано. Это может помочь кому-то визуализировать, какint
переменная помещается в частную область видимости.Другим способом было бы сказать,
Надеюсь, это поможет визуализировать происходящее.
Мне очень нравится эта функция, так как объявление
int
внутриfor
цикла делает код красивым и сжатым.источник
using
вполне нормально, хотя семантика довольно различна (возможно, поэтому она была отклонена). Обратите внимание, чтоif (true)
это избыточно. Удалите его, и у вас будет блок обзора.