Область видимости переменной C#: 'x' не может быть объявлена в этой области, потому что это даст другое значение 'x'
if(true)
{
string var = "VAR";
}
string var = "New VAR!";
в результате:
Ошибка 1 локальная переменная с именем 'var'
не может быть объявлен в этой области
потому что это дало бы иной
значение 'var', которое уже есть
используется в "дочерней" области для обозначения
что-то еще.
ничего разрушительного на самом деле, но разве это не просто неправильно? Коллега-разработчик и я задавались вопросом, должно ли первое объявление быть в другой области, поэтому второе объявление не может вмешайтесь в первую декларацию.
почему C# не может различать две области? Должна ли первая область IF не быть полностью отделена от остальной части метода?
Я не могу вызвать var из-за пределов if, поэтому сообщение об ошибке неверно, потому что первый var не имеет отношения ко второй области.
3 ответов:
проблема здесь в основном заключается в хорошей практике и предотвращении непреднамеренных ошибок. По общему признанию, компилятор C#теоретически быть спроектированы таким образом, что нет никакого конфликта между областями здесь. Однако это было бы много усилий для небольшой выгоды, как я вижу.
считайте, что если объявление
varв родительской области были до оператор if, был бы неразрешимый конфликт именования. Компилятор просто не различают следующие два случая. Анализ сделан чисто на основе области, а не порядок объявления/использования, как вы, кажется, ожидаете.теоретически приемлемый (но все еще недействительный в отношении C#):
if(true) { string var = "VAR"; } string var = "New VAR!";и неприемлемо (так как это будет скрывать родительскую переменную):
string var = "New VAR!"; if(true) { string var = "VAR"; }оба обрабатываются точно так же с точки зрения переменных и областей.
, есть ли какие-либо фактические причина в этом secenario, почему вы не можете просто дать одной из переменных другое имя? Я предполагаю (надеюсь), что ваши фактические переменные не называютсяvar, Так что я действительно не вижу в этом проблемы. Если вы все еще намерены повторно использовать одно и то же имя переменной, просто поместите их в одноуровневые области:if(true) { string var = "VAR"; } { string var = "New VAR!"; }однако это, хотя и допустимо для компилятора, может привести к некоторой путанице при чтении кода, поэтому я рекомендую против него почти в любом случае.
разве это неправильно?
нет, это совсем не так. Это правильная реализация раздела 7.5.2.1 спецификации C# "простые имена, инвариантные значения в блоках".
спецификация:
для каждого вхождения заданного идентификатор в качестве простого имени в выражение или Декларатор, в пространство объявления локальной переменной из этого события, каждый другие случаи того же идентификатор в качестве простого имени в выражение или Декларатор должны ссылаться на то же самое сущность. Это правило гарантирует, что значение имени всегда одно и то же в пределах данного блока, блок переключателя, для-команда foreach - или через оператора, или анонимная функция.
Почему C# не может различать две области?
вопрос бессмысленный; очевидно, компилятор и возможность различайте эти две области. Если компилятор не смог различить две области, то как может быть произведена ошибка? Сообщение об ошибке говорит что есть две разные области, и поэтому области были дифференцированы!
должна ли первая область IF не быть полностью отделена от остальной части метода?
нет, не должно. Область (и пространство объявления локальной переменной) определенный блоком оператор в следствии условного оператора лексически является частью внешнего блока, который определяет тело метода. Поэтому правила о содержимом внешнего блока применяются к содержимому внутреннего блока.
Я не могу вызвать var из-за пределов if, поэтому сообщение об ошибке неверно, потому что первый var не имеет никакого отношения к второй объем.
это совершенно неверно. Это показной заключить это просто потому, что локальная переменная больше не находится в области видимости, что внешний блок не содержит ошибки. Сообщение об ошибке является правильным.
ошибка здесь не имеет ничего общего с тем, перекрывает ли область любой переменной область любой другой переменной; единственное, что здесь уместно, это то, что у вас есть блок-внешний блок-в котором одно и то же простое имя используется для обозначения двух совершенно разных вещей. C# требует, чтобы простое имя один значение во всем блоке, который сначала использует его.
например:
class C { int x; void M() { int x = 123; } }это совершенно законно; область внешнего x перекрывает область внутреннего x, но это не ошибка. Что такое ошибка:
class C { int x; void M() { Console.WriteLine(x); if (whatever) { int x = 123; } } }потому что теперь простое имя " x "означает две разные вещи внутри тела M-это означает" это.x "и локальная переменная"x". Это сбивает с толку разработчиков и сопровождающих кода, когда одно и то же простое имя означает две совершенно разные вещи в блоке, так что это незаконно.
мы позволяем параллельным блокам содержать одно и то же простое имя, используемое двумя различными способами; это законно:
class C { int x; void M() { if (whatever) { Console.WriteLine(x); } if (somethingelse) { int x = 123; } } }потому что теперь единственный блок, который содержит два несогласованных использования x является внешний блок, и этот блок не напрямую содержат любое использование "x", только косвенно.
это действительно в C++, но источник для многих ошибок и бессонных ночей. Я думаю, что ребята C# решили, что лучше бросить предупреждение/ошибку, так как в подавляющем большинстве случаев это ошибка, а не то, что на самом деле хочет кодер.
здесьинтересная дискуссия о том, из каких частей спецификации эта ошибка происходит.
EDIT (некоторые примеры) - - - - -
В C++, действительно следующее (И это действительно не имеет значения, если внешнее объявление находится до или после внутренней области, оно будет просто более интересным и подверженным ошибкам, если это раньше).
void foo(int a) { int count = 0; for(int i = 0; i < a; ++i) { int count *= i; } return count; }теперь представьте, что функция на несколько строк длиннее, и может быть легко не заметить ошибку. Компилятор никогда не жалуется (не это старые времена, не уверен в более новых версиях C++), и функция всегда возвращает 0.
behaivour явно является ошибкой, поэтому было бы хорошо, если бы программа c++-lint или компилятор указали на это. Если это не ошибка, которую легко обойти, просто переименовав внутреннюю переменную.
чтобы добавить оскорбление к травме, я помню, что GCC и VS6 имели разные мнения о том, где переменная счетчика в циклах for принадлежала. Один сказал, что он принадлежал к внешней области, а другой сказал, что это не. Немного раздражает, чтобы работать на кросс-платформенный код. Позвольте мне привести вам еще один пример, чтобы сохранить мою линию подсчета.
for(int i = 0; i < 1000; ++i) { if(array[i] > 100) break; } printf("The first very large value in the array exists at %d\n", i);этот код работал в VS6 IIRC, а не в GCC. Во всяком случае, C# имеет убрали несколько вещей, что хорошо.
Comments