C#变量范围不一致?

l33*_*33t 6 c# scope

在变量范围方面,C#非常适合挑选.它怎么可能接受这个代码:

class Program
{
    int x = 0;

    void foo()
    {
        int x = 0;
        x = 1;

        Console.WriteLine(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你问我,这是一个明显的命名冲突.编译器(VS 2010)仍然接受它.为什么?

Eri*_*ert 18

C#名称隐藏的规则非常复杂.该语言允许你提到的情况,但不允许许多类似的情况.看到

http://ericlippert.com/2009/11/02/simple-names-are-not-so-simple/

有关这个复杂主题的一些信息.

为了解决您的具体问题:编译器当然可以检测到该冲突.事实上,它确实发现了这种冲突:

class P
{
    int x;
    void M()
    {
        x = 123; // The author intends "this.x = 123;"
        int x = 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

等效的C++程序将是合法的C++,因为在C++中,局部变量在声明时就进入了范围.在C#中,局部变量在整个块中都在范围内,并且在声明之前使用它是非法的.如果你尝试编译这个程序,你会得到:

error CS0844: Cannot use local variable 'x' before it is declared.
The declaration of the local variable hides the field 'P.x'.
Run Code Online (Sandbox Code Playgroud)

请参阅:本地声明隐藏该字段.编译器知道它.那么为什么在你的情况下隐藏一个字段不是错误

让我们假设为了论证它应该是一个错误.这也应该是一个错误吗?

class B
{
    protected int x;
}
class D : B
{
    void M()
    {
        int x;
    }
}
Run Code Online (Sandbox Code Playgroud)

字段x是来自B的继承的D的成员.所以这也应该是一个错误,对吧?

现在假设您有这个由Foo Corporation制作的程序:

class B
{
}
Run Code Online (Sandbox Code Playgroud)

这个程序由Bar Corporation制作:

class D : B
{
    void M()
    {
        int x;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译.现在假设Foo Corp更新他们的基类并向您发送新版本:

class B
{
    protected int x;
}
Run Code Online (Sandbox Code Playgroud)

您告诉我包含名为x的局部变量的每个派生类现在都无法编译?

那太可怕了.我们必须允许局部变量来影响成员.

如果我们要允许本地人影响基类的成员,那么不允许本地人影响类的成员就显得非常奇怪.


das*_*ght 13

这不是命名冲突:在C#中,局部变量优先于具有相同名称的实例变量,因为它们的范围更窄.

当编译器匹配名称声明的名称引用时,它使用具有最窄范围的匹配声明

有关该主题的详细信息,请参阅参考匹配文档.