为什么不能在嵌套的本地范围中声明重复的变量名?

时间:2011-05-27 18:44:46

标签: c# .net

根据最近的question,我不明白所提供的答案。看起来你应该可以做这样的事情,因为它们的范围不重叠

static void Main()
{
  {
    int i;
  }
  int i;
}

此代码无法编译,并出现以下错误:

  

名为'i'的局部变量不能在此范围内声明,因为它会给'i'赋予不同的含义,'i'已在'child'范围内用于表示其他内容

9 个答案:

答案 0 :(得分:38)

我认为到目前为止没有任何答案相当从规范中得到了关键的一线。

从第8.5.1节开始:

  

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

(强调我的。)

换句话说,“later”变量的范围包括声明之前块的部分 - 即它包含包含“早期”变量的“内部”块。

你不能引用到比其声明更早的地方的后一个变量 - 但它仍在范围内。

答案 1 :(得分:8)

“局部或常量变量的范围扩展到当前块的末尾。您不能在当前块或任何嵌套块中声明具有相同名称的另一个局部变量。” C#3.0在果壳中,http://www.amazon.com/3-0-Nutshell-Desktop-Reference-OReilly/dp/0596527578/

“块的局部变量声明空间包括任何嵌套块。因此,在嵌套块中,不可能声明一个与封闭块中的局部变量同名的局部变量。”可变范围,MSDN,http://msdn.microsoft.com/en-us/library/aa691107%28v=vs.71%29.aspx

另外,这与JavaScript和F#范围规则完全相反。

答案 2 :(得分:6)

来自C# language spec:

  

块的局部变量声明空间包括任何嵌套块。因此,在嵌套块中,不可能声明一个与封闭块中的局部变量同名的局部变量。

基本上,它是不允许的,因为在C#中,它们的范围实际上是重叠的。

编辑:为了澄清一下,C#的范围是在块级别解决的,而不是逐行解决的。因此,虽然你不能在声明之前引用代码中的变量,但它的范围一直延伸到块的开头也是如此。

答案 3 :(得分:3)

这是第一版C#中的规则。

允许重叠范围只会导致(程序员而不是编译器)的混淆。

所以它是故意禁止的。

答案 4 :(得分:3)

对于C#,ISO 23270(信息技术 - 编程 语言 - C#),§10.3(声明)说:

  

每个 switch-block for-statement foreach-statement ,或者    using-statement 为局部变量创建一个声明空间   本地常量称为局部变量声明空间。名字是   通过 local-variable-declarations 引入此声明空间   和局部常量声明

     

如果块是实例的主体   构造函数,方法或操作符声明,或者获取或设置访问器   索引器声明,在这样的声明中声明的参数是   块的本地变量声明空间的成员。

     

如果是块   泛型方法的主体,在这样的声明中声明的类型参数   是块的局部变量声明空间的成员。

     

这是一个错误   对于局部变量声明空间的两个成员具有相同的名称。   对于局部变量声明空间和嵌套本地,这是一个错误   变量声明空间包含具有相同名称的元素。

     

[注意:因此,在嵌套块中,无法声明本地   变量或常量,与局部变量或常量同名   在一个封闭的街区。可以包含两个嵌套块   只要两个块都不包含另一个,就可以使用相同名称的元素。   结束记录]

所以

public void foobar()
{
  if ( foo() )
  {
     int i = 0 ;
     ...
  }

  if ( bar() )
  {
    int i = 0 ;
    ...
  }

  return ;
}

是合法的,但

public void foobar()
{
  int i = 0 ;

  if ( foo() )
  {
     int i = 0 ;
     ...
  }

  ...

  return ;
}

不合法。就个人而言,我觉得这个限制很烦人。我可以看到发出关于作用域重叠的编译器警告,但编译错误?恕我直言,腰带和吊带太多了。我可以看到编译器选项和/或编译指示的优点(可能是-pedantic / -practical#pragma pedantic vs #pragma practicalB^))。

答案 5 :(得分:2)

这不是重叠范围的问题。在C#中,一个简单的名称并不意味着它声明的块中不止一个东西。在您的示例中,名称i表示同一外部块中的两个不同内容。

换句话说,您应该能够将变量声明移动到声明它的块内的任何位置,而不会导致作用域重叠。将您的示例更改为:

static void Main()
{
    int i;
    {
        int i;
    }
}

会导致不同i变量的范围重叠,您的示例是非法的。

答案 6 :(得分:1)

我刚刚在GCC中将其编译为C和C ++。我没有收到任何错误消息,因此它似乎是有效的语法。

您的问题被标记为.net和c。它应该被标记为c#吗?该语言可能与C有不同的规则。

答案 7 :(得分:1)

在C中,您需要将所有变量声明放在块的最开头。他们需要在开始{之后直接来到这个区块中的任何其他陈述之前。

所以你可以做的就是编译它:

static void Main()
{
  {
    int i;
  }
  {
    int i;
  }
}

答案 8 :(得分:0)

以下是MSDN .NET Documentation的答案:

  

...块的局部变量声明空间包括任何嵌套块。因此,在嵌套块中,不可能声明一个与封闭块中的局部变量同名的局部变量。