为了账号安全,请及时绑定邮箱和手机立即绑定

C#中的可变范围混淆

C#中的可变范围混淆

C#
跃然一笑 2019-09-03 15:22:53
我有两个代码示例。第一个不编译,但第二个编译。代码示例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?
查看完整描述

3 回答

?
侃侃无极

TA贡献2051条经验 获得超10个赞

这里有两个相关的规则。


第一个相关规则是:


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


(此页面上的另一个答案调出了规范中的另一个位置,我们再次将其称为。)


仅这一点就足以使其成为非法行为,但事实上,第二条规则使其成为非法行为。


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


对于给定标识符的每次出现,作为表达式或声明符中的简单名称,在局部变量声明空间内,立即将该事件的块或switch-block包含在与name-name相同的标识符中。直接封闭块或switch-block中的表达式或声明符必须引用同一实体。此规则确保名称的含义在给定块,switch块,for-,foreach-或using-statement或匿名函数中始终相同。


你还需要知道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。


此外,两个“i”变量都在相同的局部变量声明空间中,两个“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中的不一致用法视为相关。


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


因此,这是合法的。


查看完整回答
反对 回复 2019-09-03
?
慕的地8271018

TA贡献1796条经验 获得超4个赞

来自C#语言规范......

在local-variable-declaration中声明的局部变量的范围是声明发生的块。在局部变量的local-variable-declarator之前的文本位置引用局部变量是错误的。在局部变量的范围内,声明另一个具有相同名称的局部变量或常量是编译时错误。

在代码示例1中,i和objX都在函数的范围内声明,因此该函数内任何块中的其他变量都不能与它们共享名称。在代码示例2中,两个objX都在for循环内声明,这意味着它们不违反不在另一个声明的内部作用域中重新声明局部变量的规则。


查看完整回答
反对 回复 2019-09-03
?
饮歌长啸

TA贡献1951条经验 获得超3个赞

您可以在非重叠范围中使用相同的变量名称。但是,如果一个范围与另一个范围重叠,则不能在两个范围内声明相同的变量。这样做的原因是为了防止您在内部作用域中意外使用已经使用过的变量名,就像i在第一个示例中一样。这并不是真的要防止objX错误,因为这肯定不会令人困惑,但错误是规则应用的结果。编译器objX在其声明之前和声明之后的整个声明范围内都被视为具有出处,而不仅仅是声明之后。

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

从个人角度来说,我发现这个错误令人讨厌,并且更喜欢C / C ++允许你做任何你想要的方式,混淆被诅咒。


查看完整回答
反对 回复 2019-09-03
  • 3 回答
  • 0 关注
  • 324 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信