4.4 代码块、作用域和声明空间
代码块经常被称为作用域,但两个术语并不完全可以互换。具名事物的作用域是源代码的一个区域。可在该区域使用非限定名称(前面不加限定前缀的名称)引用该事物。局部变量的作用域就是封闭它的代码块。这正是经常将代码块称为“作用域”的原因。
作用域经常和声明空间混淆。声明空间是具名事物的逻辑容器。该容器中不能存在同名的两个事物。代码块不仅定义了作用域,还定义了局部变量声明空间。同一个声明空间中,不允许声明两个同名的局部变量。在声明局部变量的代码块外部,没有办法用局部变量的名称引用它,这时说局部变量“超出作用域”。类似地,不能在同一个类中声明具有Main()签名的两个方法。(方法的规则有一些放宽:在同一个声明空间中,允许存在签名不同的两个同名方法。方法的签名包括它的名称和参数的数量/类型。)
简单地说,作用域决定一个名称引用什么事物,而声明空间决定同名的两个事物是否冲突。在代码清单4.27中,是在if语句主体声明局部变量message,这就将它的作用域限制在if主体。要纠正错误,必须在if语句外部声明该变量。
代码清单4.27 变量在其作用域外无法访问
输出4.15展示了结果。
输出4.15
局部变量名称必须唯一的声明空间包含最初声明局部变量的块中以文本形式包含的所有子代码块。C#编译器禁止一个代码块中声明(或作为参数声明)的局部变量在其子代码块中重复声明。总之,一个变量的声明空间是当前代码块以及它的所有子代码块。在代码清单4.27中,由于args和playerCount在方法的代码块(方法主体)中声明,所以在这个代码块的任何地方(包括子代码块)都不能再次声明。
message这个名称仅在if块中可用,在外部不能使用。类似地,playerCount在整个方法(包括if和else子代码块)中引用的都是同一个变量。
语言对比:C++——局部变量作用域
在C++中,对于块中声明的局部变量,它的作用域从声明位置开始,到块尾结束。声明前对局部变量的引用会失败,因为局部变量此时不在作用域内。如果此时有另一个同名的事物在作用域中,C++会将名称解析成对那个事物的引用,而这可能不是你的原意。C#的规则稍有不同,对于声明局部变量的那个块,局部变量都在作用域中,但声明前引用它属于非法。换言之,此时局部变量合法存在,但使用非法。只有在声明后的位置使用才合法。这是C#防止像C++那样出现不容易察觉之错误的众多规则之一。