在C#可变范围混乱(Variable scope confusion in C#)

2019-06-17 18:30发布

我有两个代码示例。 先不编译,但第二次却。

代码示例1( 不编译)

public void MyMethod(){
    int i=10;

    for(int x=10; x<10; x++) {
        int i=10; // Point1: compiler reports error
        var objX = new MyOtherClass();
    }

    var objX = new OtherClassOfMine(); // Point2: compiler reports error
}

我明白为什么编译器在报告错误Point1 。 但我不明白为什么它在报告错误Point2 。 如果你说,这是因为里面MSIL组织的,那为什么第二个代码示例编译?

代码样品2( 编译)

public void MyMethod(){

    for(int x=10; x<10; x++) {
        int i=10; 
        var objX = new MyOtherClass();
    }

    for(int x=10; x<10; x++) {
        int i=10; 
        var objX = new MyOtherClass();
    }
}

如果变量范围的简单规则,代码示例2应用,那么我们为什么不这些规则同样适用于代码示例1?

Answer 1:

这里有两个相关的规则。

第一个相关的规则是:

它是一个局部变量声明空间和嵌套的局部变量声明空间来包含具有相同名称的元件的错误。

(而这个页面上的其他答案召唤出在我们再次调用此超出规定的其他位置。)

这本身就足以让这个非法的,但实际上第二个规则,使这一非法。

C#中的第二个相关的规则是:

对于给定的标识符如在表达式或声明简单名称的每次出现,局部变量声明空间内,立即封闭块,或切换-块发生,相同的标识符作为一个简单的名称中的每一个其它存在的立即封闭块或开关块内的表达式或声明必须是指相同的实体。 此规则确保一个名称的含义总是给定块,开关块,换,foreach-或使用语句,或匿名函数中相同。

你还需要知道,因为虽然有“隐形矫正”,围绕整个事情for循环进行处理。

现在我们知道,让我们注释你的代码:

public void MyMethod()
{ // 1
    int i=10; // i1
    { // 2 -- invisible brace
      for(int x=10; x<10; x++) // x2
      { // 3
        int i=10;  // i3
        var objX = new MyOtherClass(); // objX3
      } // 3
    } // 2
    var objX = new OtherClasOfMine(); // objX1
} // 1

你有三个“简单名称”,I,X和物objx。 你有五个变量,我已经标记为I1,X2,I3,objX3和objX1。

包含用途的i和物objx是块1。因此,块1内的最外面的块,i和物objx必须始终指的是相同的东西。 但他们没有。 有时候,我指的是I1,有时它指的是酷睿i3。 同样的,物objx。

X,但是,永远只能是指X2,在每一个块。

此外,无论是“我”的变量是在同一个局部变量声明空间,因为都是“物objx”变量。

因此,该程序是在几个方面的错误。

在你的第二个程序:

public void MyMethod()
{ // 1
    { // 2 -- invisible 
      for(int x=10; x<10; x++)   // x2
      { // 3
        int i=10;  // i3
        var objX = new MyOtherClass(); // objX3
      } //3 
    } // 2
    { // 4 -- invisible
      for(int x=10; x<10; x++)  // x4
      { // 5
        int i=10;  // i5
        var objX = new MyOtherClass();  // objX5
      } //5
   } // 4
} // 1

现在你有再而三个的简单的名称,以及六个变量。

该第一包含简单的名称为x的使用最外面的块是块2和4.在整个块2,x指X2。 整个块4,x指X4。 因此,这是合法的。 同样与i和物objx - 它们在块3和5使用,并且意指在每个不同的事情。 但无处是用于在整个同一块意味着两个不同的东西一样简单的名称。

现在,你可能会注意到, 在考虑所有的块1,x被用于指x2和x4。 但是,没有任何的x提到,里面是块1,但不也是另一种块内。 因此,我们不指望在块1的相关不一致的用法。

此外,没有一个声明空间的非法方式重叠。

因此,这是合法的。



Answer 2:

从C#语言规范...

在局部变量声明中表示的局部变量的范围是在该声明所在的块。 这是指一个局部变量在先于局部变量的局部变量声明的文本位置的误差。 在一个局部变量的范围内,这是一个编译时错误声明另一个局部变量或常量具有相同的名称。

在代码样品1,i和物objx的函数的范围被声明,那么在该函数内的任何块没有其他变量可以与他们共享的名称。 在代码示例2中,objXs声明的for循环中,这意味着只要不违反不从另一声明重新声明在内部范围的局部变量的规则。



Answer 3:

你被允许在非重叠的范围,使用相同的变量名。 如果一个范围彼此重叠,但是,你不能在这两个声明的同一个变量。 其原因是为了防止你在内部范围不小心使用已经使用的变量名,像你做i的第一个例子。 这不是真的,防止objX错误,因为那会,诚然,不是很混乱,但这个错误是如何应用规则的结果。 该编译器将objX具有贯穿其所之前和它的声明后宣布,不只是后范围出处。

在第二个例子中的两个for循环具有独立的,非重叠的范围,所以你可以自由地重新使用iobjX在第二循环中。 它也可以重新使用的原因x为你的循环计数器。 显然,这将是一个愚蠢的限制,如果你不得不做出了不同的名字为每for(i=1;i<10;++i)中的函数式的循环。

就我个人而言,我觉得这是错误讨厌,喜欢允许的C / C ++的方式你做任何你想要的,混乱被定罪。



Answer 4:

你不应该得到一个编译错误与第二样品。 尝试重命名变量,以不同的字母/名称和重新编译,因为它可能使另一个问题很有可能你已经错过了一个大括号,并改变了变量的作用域范围内的代码。



文章来源: Variable scope confusion in C#
标签: c# scope