为什么C#不允许我在不同的作用域中使用相同的变量名?
例如:
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Matrix matrix = new Matrix();
编译器警告我说:
“名为' matrix
'的局部变量不能在此范围内声明,因为它会给' matrix
'赋予不同的含义,' matrix
'已经在'子'范围内用于表示其他内容。
这些变量是不是在不同的范围内,所以我无法从if语句之外访问第一个matrix
?
更新:2011年以下的答案对于早期版本的C#是正确的; 在更新的版本中,规则描述的答案已经从C#中删除。 设计团队确定,即使在我极大地改进了错误信息以更明确地诊断问题之后,规则导致出现类似此类问题的开发人员之间的混淆更多,而不是错误的程序所预防的情况。
迄今给出的答案非常混乱。 通过阅读错误信息开始正确分析问题。 错误消息告诉你什么是错误的:
“名为'矩阵'的局部变量不能在此范围内声明,因为它会给'矩阵'赋予不同的含义,'矩阵'已经在'子'范围内用于表示其他内容。
仔细阅读。 它告诉你C#的哪个规则正在被违反,即你不允许在同一个范围内使用同一个名称来引用两个不同的东西。 (实际上,错误信息有点不对,它应该说“局部变量声明空间”,它在“范围”中表示,但这很罗嗦。)
此规则在C#4.0规范7.6.2.1:简单名称,块中的不变含义中进行了说明。
(在重叠的声明空间中有两个同名的局部变量也是非法的,编译器也可以报告错误,但是在这种情况下它会报告更一般的错误。)
这些变量是不是在不同的范围内,所以我无法从if语句之外访问第一个矩阵?
是。 该声明是真实的,但无关紧要。 这里的错误是,在相同的局部变量声明空间中使用了相同的简单名称来引用两个不同的东西。
考虑这种情况:
class C
{
int x;
void M()
{
x = 10; // means "this.x"
for(whatever)
{
int x = whatever;
}
}
}
同样的交易。 这里的错误是,在外部声明空间中使用简单名称“x”来引用this.x,并且在内部声明空间中使用它来表示“局部变量”。 使用相同的简单名称在同一个声明空间中引用两个不同的东西 - 请记住,内部声明空间是外部声明空间的一部分 - 既混乱又危险,因此是非法的。
由于显而易见的原因令人困惑; 人们有一个合理的期望,即在整个首次使用的声明空间中,名称意味着相同的东西。 这很危险,因为小代码编辑很容易改变含义:
class C
{
int x;
void M()
{
int x;
x = 10; // no longer means "this.x"
for(whatever)
{
x = whatever;
}
}
}
如果首次使用简单名称的声明空间不重叠,则简单名称引用不同的事物是合法的:
class C
{
int x;
void M()
{
{
x = 10; // means "this.x"
}
for(whatever)
{
int x = whatever; // Legal; now the
}
}
}
欲了解更多信息,以及关于油炸食品的有趣故事,请参阅
http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/
我相信这是为了避免模糊的错误或难以阅读的代码。
在方法范围和子范围之间使用相同名称的变量可能会导致代码很难读取,因为变量类型和更糟糕的含义可能会更改,并且读者的唯一提示将是变量。
不过,我也可以告诉你,由C#编译器为方法生成的IL将把所有变量声明都放在顶部,所以这个决策驱动程序可能会简化编译器的变量解析树。
事实上,你可以在MSDN上找到这个:
名称的范围是程序文本的区域,在该区域中可以引用由名称声明的实体而不用限定名称。 范围可以嵌套,并且内部范围可以从外部范围重新声明名称的含义。 ( 但是,这并没有消除3.3节所强加的限制,即在一个嵌套块中,不可能在封闭块中声明一个与本地变量具有相同名称的本地变量。 )然后,来自外部作用域的名称是据说隐藏在内部作用域覆盖的程序文本区域中,只有通过限定名称才能访问外部名称。
重点补充。
而从第3.3节来看:
每个块或开关块为局部变量和常量创建一个不同的声明空间。 通过局部变量声明和局部常量声明将名称引入此声明空间。 如果块是实例构造函数,方法或运算符声明的主体,或者是索引器声明的get或set访问器,则在此声明中声明的参数是块的局部变量声明空间的成员。 块的局部变量声明空间包含任何嵌套块。 因此,在嵌套块中,不可能在封闭块中声明与本地变量具有相同名称的局部变量。
重点补充。
所以,事情是,虽然范围不同,但可变空间是相同的。
你总是可以这样做......
void YourMethod()
{
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
{
Matrix matrix = new Matrix();
}
}
...每一组大括号{}
允许您嵌套另一个级别的范围。 你遇到的问题是嵌套范围包括父母的范围。 如果你声明一个siblng作用域,它将能够在同一个父对象中重用变量。 但正如其他人所指出的,这可能会在以后变得混乱。
上一篇: Why doesn't C# allow me to use the same variable name in different scopes?