可能重复:
c#开关语句中的变量声明
Switch案例中额外支架的用途是什么?
今天我在写一小段代码,在调试时,VS打了我一巴掌,告诉我我的局部变量名称犯了一个大错误:"一个名为‘I’的局部变量已经在这个范围中定义了"。
MyEnum enumerator = MyEnum.B;
switch (enumerator)
{
case MyEnum.A:
Int32 i = 0;
// DoStuffsA();
break;
case MyEnum.B:
Double i = 0D;
// DoStuffsB();
break;
}
所以我说:"好吧,VS,让我稍后解决它,我想先确定我的案例范围,因为我更喜欢它们!"。所以我做了整容手术。。。但突然VS停止抱怨这个错误:
MyEnum enumerator = MyEnum.B;
switch (enumerator)
{
case MyEnum.A:
{
Int32 i = 0;
// DoStuffsA();
break;
}
case MyEnum.B:
{
Double i = 0D;
// DoStuffsB();
break;
}
}
好的。。。我知道"scope"的含义,我知道我产生了两个不同的scope。问题是我不知道switch语句是如何翻译成IL代码的,我一直认为无论是否使用大括号,所有的case语句都被放在switch作用域中。所以…下面的怪事是可以编译的,对吧?
MyEnum enumerator = MyEnum.B;
switch (enumerator)
{
case MyEnum.A:
String s = "Hello!";
Console.WriteLine(s);
break;
case MyEnum.B:
s = "Goodbye!";
Console.WriteLine(s);
break;
}
但不是以下一个:
MyEnum enumerator = MyEnum.B;
switch (enumerator)
{
case MyEnum.A:
{
String s = "hello";
Console.WriteLine(s);
break;
}
case MyEnum.B:
{
s = "goodbye";
Console.WriteLine(s);
break;
}
}
有人能更好地解释编译器在这种情况下的行为吗?非常感谢!
在不同的case
块中添加{}
时,将引入作用域。
没有它们,所有case
块都在一个范围内。
在最后两个例子中,使用s
-第一个很好,因为s
是在case
中为MyEnum.A
声明的,所以可以在MyEnum.B
中使用,但使用大括号时,MyEnum.A
中的声明在其自己的范围内,在外部不可见-所以在MyEnum.B
中,s
是未知的,需要重新声明。
首先,到IL的翻译有些无关紧要。IL根本没有相同的范围概念。这一切都与C#语言规范有关。
实际上,这很简单:局部变量的作用域是声明它的块,当另一个同名局部变量在作用域中时,不能声明一个局部变量。
-
在您的第一段代码中,
i
的作用域是整个switch语句。您的第二个声明试图在同一范围内声明另一个i
变量,因此它失败了。 -
在第二段代码中,每个
i
变量的作用域只是由大括号创建的块——它们处于完全独立的作用域中,没有嵌套,所以没关系。 -
在您的第三段代码中,变量
s
在第二种情况的作用域中,因为它的作用域是整个switch语句,所以可以使用它 -
在您的第四段代码中,变量
s
在声明它的块的作用域中仅(在情况A中(,因此在情况B中不在作用域中。
我强烈建议不要使用像第三段代码那样的代码。这会使许多人感到困惑。如果你真的想要一个在多个情况下都有效的变量,我会在switch语句之前声明它。
将break
放在大括号内会导致它断裂到大括号的末端,此时case
会穿过。您需要大括号之外的break
语句。例如
case MyEnum.A:
{
String s = "hello";
Console.WriteLine(s);
}
break;