Область видимости переменной C#: 'x' не может быть объявлена в этой области, потому что это даст другое значение 'x'



if(true)
{
string var = "VAR";
}

string var = "New VAR!";


в результате:




Ошибка 1 локальная переменная с именем 'var'
не может быть объявлен в этой области
потому что это дало бы иной
значение 'var', которое уже есть
используется в "дочерней" области для обозначения
что-то еще.




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



почему C# не может различать две области? Должна ли первая область IF не быть полностью отделена от остальной части метода?



Я не могу вызвать var из-за пределов if, поэтому сообщение об ошибке неверно, потому что первый var не имеет отношения ко второй области.

548   3  

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

    Ничего не найдено.