Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#变量范围不一致?_C#_Scope - Fatal编程技术网

C#变量范围不一致?

C#变量范围不一致?,c#,scope,C#,Scope,当涉及变量范围时,C#相当挑剔。它如何可能接受此代码: class Program { int x = 0; void foo() { int x = 0; x = 1; Console.WriteLine(x); } } 如果你问我,那显然是命名冲突。编译器(VS2010)仍然接受它。为什么?这不是命名冲突:在C#中,局部变量优先于具有相同名称的实例变量,因为它们的名称较窄 当编译器将名称引用与名称声明相匹配

当涉及变量范围时,C#相当挑剔。它如何可能接受此代码:

class Program
{
    int x = 0;

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

        Console.WriteLine(x);
    }
}

如果你问我,那显然是命名冲突。编译器(VS2010)仍然接受它。为什么?

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

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


有关此主题的详细信息,请参阅的文档。

没有命名冲突。编译器始终采用最接近的/最小范围变量

在本例中,这是您在
foo
中声明的x变量。 每个变量都可以以特定的方式访问,因此没有命名冲突


如果要访问外部x,可以使用
this.x

,因为规则是,如果局部变量和类成员之间存在冲突,则局部变量具有更高的优先级。

这并不含糊,局部变量将是假定在函数中引用的变量。如果需要获取类变量,则此.x允许名称解析

这很正常

在构造函数中,我经常使用相同的

public Person(string name) {
  this.name = name;
}
否则就不可能声明像成员变量一样命名的方法参数。

C#name隐藏的规则非常复杂。该语言允许您提到的情况,但不允许许多类似的情况。看

关于这个复杂问题的一些信息

为了解决您的特定问题:编译器当然可以检测到这种冲突。事实上,它确实检测到了这种冲突:

class P
{
    int x;
    void M()
    {
        x = 123; // The author intends "this.x = 123;"
        int x = 0;
    }
}
<> P>等效的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'.
请参见:本地声明隐藏字段。编译器知道这一点。那么,在您的情况下,为什么隐藏字段不是一个错误呢

为了论证起见,让我们假设这应该是一个错误。这也应该是一个错误吗

class B
{
    protected int x;
}
class D : B
{
    void M()
    {
        int x;
    }
}
字段x通过从B继承而成为D的成员。所以这也应该是一个错误,对吗

现在假设您有一个由Foo公司制作的程序:

class B
{
}
class D : B
{
    void M()
    {
        int x;
    }
}
由Bar公司制作的这个节目:

class B
{
}
class D : B
{
    void M()
    {
        int x;
    }
}
这就是汇编。现在假设Foo Corp更新其基类并向您发送新版本:

class B
{
    protected int x;
}
您是说每个包含名为x的局部变量的派生类现在都应该无法编译吗?

那太可怕了。我们必须允许局部变量对成员进行阴影处理

如果我们要允许局部变量对基类的成员进行阴影处理,那么不允许局部变量对类的成员进行阴影处理就显得非常奇怪。

C#4.0规范中提到了通过嵌套隐藏作用域:

3.7.1.1通过嵌套隐藏

通过嵌套进行名称隐藏可能是由于在名称空间中嵌套名称空间或类型,例如 类或结构中嵌套类型的结果,以及 参数和局部变量声明。在这个例子中

在F方法中,实例变量i被局部变量隐藏 变量i,但在G方法中,i仍然引用实例 变数

当内部作用域中的名称隐藏外部作用域中的名称时 范围,则隐藏该名称的所有重载实例

在这个例子中

调用F(1)调用在内部声明的F,因为所有外部 F的出现被内部声明隐藏。同样 因此,调用F(“Hello”)会导致编译时错误


您可以参考
x
this.x
,所以没有问题。实际上这是一致的。如果void foo()函数中只有x=0,那么它将从x中提取您先前定义的变量。因为在方法中有int x=0,您可以为所有意图实例化一个新变量。但是如果在foo方法之外查看x的值,它仍然是0,因为您在不同的作用域中。如果您不喜欢使用与类成员同名的局部变量,则可以获取ReSharper和。是的,从您的角度来看,这是命名冲突,但这是一个由语言设计者预先确定的解决方案;局部变量优先于实例变量。编译器接受它的原因是因为它在语言定义中是有效的。我怀疑定义优先顺序的原因是,决定如何处理这种情况相当容易和直观。对于其他情况(两个局部变量的作用域重叠等),情况就不是这样了,它被标记为一个错误。你可能也会发现有趣的事情。这让我很困惑。由于C#不允许C/C++允许的许多命名冲突,我希望上述场景也能做到这一点。@nopsloider:我添加了一些文本,解释为什么这是个坏主意。