Почему С# не позволяет мне использовать одно и то же имя переменной в разных областях?
Как например:
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Matrix matrix = new Matrix();
Компилятор предупреждает меня, говоря:
"Локальная переменная с именем" matrix
"не может быть объявлена в этой области, потому что она будет иметь другое значение" matrix
", которое уже используется в области" child ", чтобы обозначить что-то еще.
Не эти переменные в разных областях, поэтому я не смог бы получить доступ к первой matrix
извне оператора if?
Ответы
Ответ 1
Ответы, данные до сих пор, очень сбивают с толку. Правильный анализ проблемы начинается с чтения сообщения об ошибке. Сообщение об ошибке сообщает вам, что на самом деле неправильно:
"Локальная переменная с именем" matrix "не может быть объявлена в этой области, потому что она придаст другой смысл" матрице ", которая уже используется в области" child ", чтобы обозначить что-то еще.
Прочитайте внимательно . Он сообщает вам, какое именно правило С# нарушается, а именно, что вам не разрешено использовать одно и то же имя для обозначения двух разных вещей в одной и той же области. (На самом деле, сообщение об ошибке несколько неверно, оно должно сказать "локальное пространство декларации переменных", где указано "scope", но это довольно многословно.)
Это правило задокументировано в спецификации С# 4.0, раздел 7.6.2.1: Простые имена, Инвариантное значение в блоках.
(Также недопустимо иметь две локальные переменные с одним и тем же именем в перекрывающихся пространствах объявлений. Компилятор также может сообщать об этой ошибке, но в этом случае он сообщает об общей ошибке.)
Не эти переменные в разных областях, поэтому я не смог бы получить доступ к первой матрице извне оператора if?
Да. Это утверждение верно, но не имеет значения. Ошибка здесь заключается в том, что одно и то же простое имя использовалось для обозначения двух разных вещей в одном и том же пространстве объявления переменных переменных.
Рассмотрим этот сценарий:
class C
{
int x;
void M()
{
x = 10; // means "this.x"
for(whatever)
{
int x = whatever;
}
}
}
Такая же сделка. Ошибка здесь заключается в том, что простое имя "x" использовалось во внешнем пространстве декларации для ссылки на this.x и использовалось во внутреннем пространстве декларации для обозначения "локальной переменной". Используя одно и то же простое имя, чтобы ссылаться на две разные вещи в одном и том же пространстве декларации - помните, внутреннее пространство декларации является частью внешнего, является как запутанным, так и опасным, и поэтому является незаконным.
Это сбивает с толку по понятным причинам; есть разумное ожидание того, что имя будет означать одно и то же везде во всем пространстве декларации, в котором оно впервые используется. Это опасно, поскольку небольшие изменения кода подвержены изменению значения:
class C
{
int x;
void M()
{
int x;
x = 10; // no longer means "this.x"
for(whatever)
{
x = whatever;
}
}
}
Если пространства объявлений, в которых простые имена сначала используются, не перекрываются, тогда для простых имен легально ссылаться на разные вещи:
class C
{
int x;
void M()
{
{
x = 10; // means "this.x"
}
for(whatever)
{
int x = whatever; // Legal; now the
}
}
}
Для получения дополнительной информации и интересной истории о жареной пище см.
http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/
Ответ 2
Я считаю, что это делается для того, чтобы избежать неясных ошибок или кода, который трудно читать.
Использование одного и того же имени переменной между областью метода и дочерней областью может привести к тому, что код очень трудный для чтения, поскольку тип переменной и, что еще хуже, может измениться, и единственный намек на читателя будет объявлением типа ключевое слово перед переменной.
Однако я также могу сказать, что IL, сгенерированный для методов компилятором С#, будет содержать все объявления переменных сверху, поэтому, возможно, этот драйвер решения должен упростить дерево синтаксического анализа переменных для компилятора.
Фактически вы можете найти это в MSDN:
Объем имени - это область текст программы, в пределах которого он можно сослаться на объект объявленный именем без квалификация имени. Области могут быть вложенным, а внутренний объем может переопределить значение имени из внешний охват. (Это не так, однако, удалите ограничение введенный Раздел 3.3, что в пределах вложенный блок невозможно объявить локальную переменную с тем же имя как локальная переменная в закрывающий блок.). Имя из внешний объем затем считается скрытым в области охвата текста программы по внутреннему объему и доступ к внешнее имя возможно только присвоить имя.
Добавлен акцент.
И, из раздела 3.3:
Каждый блок или блок-блок создает другое пространство декларации для локального переменных и констант. Имена введенные в это пространство декларации через локальные переменные-объявления и локальные константные объявления. Если block - это тело экземпляра конструктор, метод или оператор декларация или получение или установка доступа для объявления индексатора, параметры, объявленные в таком декларация являются членами блока локальное пространство декларации переменных. локальное пространство объявления переменной переменной блок включает любые вложенные блоки. Таким образом, внутри вложенного блока это не можно объявить локальную переменную с тем же именем, что и локальная переменная в закрывающем блоке.
Добавлен акцент.
Итак, дело в том, что в то время как области различаются, пространство переменных одинаково.
Ответ 3
Вы всегда можете это сделать...
void YourMethod()
{
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
{
Matrix matrix = new Matrix();
}
}
... Каждый набор фигурных скобок {}
позволяет вам вложить еще один уровень охвата. Проблема, с которой вы сталкиваетесь, заключается в том, что вложенные области включают сферу их родителей. Если вы объявите сферу siblng, она сможет повторно использовать переменные внутри одного и того же родителя. Но, как указывали другие, это может запутаться позже.
Ответ 4
Представьте, что человек пытается прочитать этот код.
С точки зрения другого разработчика, пытающегося прочитать ваш код, вы можете понять, как смущать его было бы иметь две разные переменные с тем же именем? Даже если они представляют одно и то же, слишком сложно справиться с двумя вещами с тем же именем.
Ответ 5
Matrix matrix = new Matrix();
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Представьте, что это вместо этого написано так, это немного более очевидно, я бы подумал, почему это не допустимо, так как второй экземпляр, очевидно, следует считать столкновением. Невозможность доступа к внешним переменным в дочерних областях была бы плохой.
Из MSDN "A: Это правильное поведение и рассматривается в разделе 3.7 спецификации языка. В нем говорится:" Область локальной переменной, объявленной в объявлении локальной переменной (8.5.1), является блоком в котором происходит объявление "...." Такое поведение позволяет сделать неправильное повторное использование имен переменных (например, в разрезе и вставке) менее вероятным". (Http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-ti-use-the-same-variable-as-an-inner-loop-does.aspx)