C#变量范围:'x'不能在这个范围内声明,因为它会给'x'赋予不同的含义

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

string var = "New VAR!";

这将导致:

错误1名为'var'的局部变量不能在此范围内声明,因为它会给'var'赋予不同的含义,'var'已用于'子'范围内以表示其他内容。

没有什么真正的地球震碎,但这不是明显的错误? 一位开发人员和我想知道第一个声明是否应该在不同的范围内,因此第二个声明不能干扰第一个声明。

为什么C#无法区分这两个范围? 第一个IF范围是否应该与方法的其余部分完全分开?

我无法从if外调用var,所以错误信息是错误的,因为第一个var在第二个范围中没有相关性。


这里的问题很大程度上是良好的做法之一,并防止无意的错误。 无可否认,C#编译器理论上可以设计成在这里范围之间没有冲突。 正如我所看到的那样,这对于微小的收益将是很大的努力。

考虑如果父范围内的var声明在if语句之前,那么会有一个无法解析的命名冲突。 编译器根本不区分以下两种情况。 分析完全基于范围,而不是声明/使用的顺序,正如您似乎期待的那样。

理论上可以接受的(但就C#而言仍然无效):

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

string var = "New VAR!";

和不可接受的(因为它会隐藏父变量):

string var = "New VAR!";

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

在变量和范围上都被完全相同地对待。

现在,在这个场景中是否有任何实际的原因,为什么你不能给一个变量赋予一个不同的名字? 我假设(希望)你的实际变量不叫var ,所以我不认为这是一个问题。 如果您仍然打算重用相同的变量名称,只需将它们放入同级作用域中即可:

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

{
    string var = "New VAR!";
}

然而,尽管对编译器有效,但在阅读代码时可能会导致一些混淆,因此几乎在任何情况下都建议不要这样做。


这不是真的错吗?

不,这根本没有错。 这是C#规范第7.5.2.1节“简单名称,块中不变含义”的正确实现。

该规范指出:


对于给定标识符在表达式或声明符中作为简单名称的每次出现,在该出现的局部变量声明空间内,与表达式或声明符中的简单名称相同的标识符的每一次出现都必须指向相同的标识符实体。 该规则确保名称的含义在给定块,开关块,for-,foreach或using语句或匿名函数中始终保持相同。


为什么C#无法区分这两个范围?

这个问题是无意义的; 显然编译器能够区分这两个范围。 如果编译器无法区分这两个范围,那么错误如何产生? 该错误消息说有两个不同的范围,因此范围已被区分!

第一个IF范围不应该与其余的方法完全分开吗?

不,它不应该。 由条件语句在条件语句的结果中定义的作用域(和局部变量声明空间)在词法上是外部块的一部分,它定义了方法的主体。 因此,关于外部块的内容的规则适用于内部块的内容。

我无法从if外调用var,所以错误信息是错误的,因为第一个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体内的两个不同的东西 - 它意味着“this.x”和局部变量“x”。 开发人员和代码维护人员感到困惑的是,同一个简单名称在同一个块中意味着两个完全不同的东西,因此这是非法的。

我们确实允许平行块包含以两种不同方式使用的相同简单名称; 这是合法的:

class C 
{
    int x;
    void M()
    { 
        if (whatever)
        {
            Console.WriteLine(x);
        }
        if (somethingelse)
        {
            int x = 123;
        }
    }
}

因为现在唯一包含x的两个不一致用法的块是外部块,并且该块不直接包含“x”的任何用法,只是间接地


这在C ++中是有效的,但却是许多错误和不眠之夜的源头。 我认为C#人员决定抛出警告/错误更好,因为在绝大多数情况下,这是一个错误,而不是编码器实际需要的东西。

这里有一个有趣的讨论,说明这个错误来自哪个部分。

编辑(一些例子)-----

在C ++中,以下内容是有效的(如果外部声明位于内部作用域之前或之后,它并不重要,如果它在前面,它会更有趣并且容易出错)。

void foo(int a)
{
    int count = 0;
    for(int i = 0; i < a; ++i)
    {
        int count *= i;
    }
    return count;
}

现在想象这个函数再长几行,可能很容易发现错误。 编译器从不抱怨(不是旧的时代,不确定C ++的新版本),并且函数总是返回0。

行为显然是一个错误,所以如果一个c ++ - lint程序或者编译器指出了这一点,那将是一件好事。 如果它不是bug,只需重命名内部变量即可轻松解决它。

为了增加伤害,我记得GCC和VS6对for循环中counter变量的属性有不同的看法。 一个说它属于外部范围,另一个说它没有。 有点讨厌跨平台代码工作。 让我再举一个例子来保持我的生产线数量。

for(int i = 0; i < 1000; ++i)
{
    if(array[i] > 100)
        break;
}

printf("The first very large value in the array exists at %dn", i);

此代码在VS6 IIRC中工作,而不是在GCC中工作。 无论如何,C#已经清理了一些东西,这很好。

链接地址: http://www.djcxy.com/p/53053.html

上一篇: C# variable scoping: 'x' cannot be declared in this scope because it would give a different meaning to 'x'

下一篇: Why can't I declare a variable with the same name in different scopes in C#?