Variable declaration in a C# switch statement
为什么在C switch语句中,对于多个情况下使用的变量,只在第一个情况下声明它?
例如,以下引发错误"名为"variable"的局部变量已在此范围内定义"。
1 2 3 4 5 6 7 8 9
| switch (Type)
{
case Type.A:
string variable ="x";
break;
case Type.B:
string variable ="y";
break;
} |
但是,根据逻辑,如果类型是Type.B,则不应点击初始声明。switch语句中的所有变量是否都存在于单个作用域中,并且在处理任何逻辑之前是否创建/分配了这些变量?
- 真正丑陋的是人们这样做:switch (Type) { case Type.A: string variable ="x"; break; case Type.B: variable ="y"; break; }。
- @请详细说明。
- @zazkapulsk应该首先声明一个变量,然后在开关中使用它:string variable = null; switch (Type) { case Type.A: variable ="x"; break; case Type.B: variable ="y"; break; }。
- 我认为一个案子不是一个新的范围是非常愚蠢的。添加case x: {...}是非常难看的。在开关之前声明变量更糟糕。我认为这是C设计上的不足。
- 我不敢相信我今天所学的。我不敢相信,这太不合逻辑了,我还是不敢相信。对我来说,这是C中的设计缺陷,因为在第1种情况下声明的变量在第二种情况下是可见的,即使没有使用括号也是没有意义的。逻辑上,如果第一个case块不为true,则不应命中它,这意味着第二个case块在使用=error时应取消声明变量。但是没有。代码嗅觉?
- 今天我还是对这个设计缺陷很恼火!
如果希望变量的作用域是特定的大小写,只需将大小写包含在自己的块中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| switch (Type)
{
case Type.A:
{
string variable ="x";
/* Do other stuff with variable */
}
break;
case Type.B:
{
string variable ="y";
/* Do other stuff with variable */
}
break;
} |
- 注意:如果支撑只包含第一个块,而不是第二个块,则此操作不起作用。在这种情况下,第二个&171;变量&187;仍然发出错误,尽管范围不同。看起来像个虫子。
- @嗨,安吉尔:那不是虫子。不能在块或其嵌套块内声明多个同名的局部变量。实际上,嵌套块"包含"在封闭块中声明的局部变量-即使声明在文件的后面以词法形式出现。对于switch语句以外的构造也是如此。见C语言规范的3.3
- 我想我明白了:如果变量存在于块中,那么我就不能再在嵌套块中使用相同的名称,即使嵌套块位于变量声明的更高位置。这是不合理的,应该是一个bug,但是刻在文档中的bug会成为一个特性吗?
我认为这与变量的整体范围有关,它是在开关级别定义的块级范围。
就个人而言,如果您在示例中将某个值设置为某个开关内的某个值,以便它真正具有任何益处,那么您无论如何都希望在该开关外声明它。
- 沿着支架走。变量只存在于第一次声明变量的最内层大括号中。
- 作为一个来自VB世界的人,这是我有点讨厌switch声明的原因之一。其他原因包括每起案件后必须向break;,并且没有与Case 1, 2, 3、Case 4 To 10或Case Is > 10类似的东西。
- @ahmedabdelhamed,您可以通过switch fall-through语句来实现这一点:stackoverflow.com/questions/174155/…
是的,作用域是整个开关块——不幸的是,IMO。但是,您可以在单个案例中添加大括号,以创建较小的作用域。至于它们是否被创建/分配,堆栈框架有足够的空间来容纳一个方法中的所有局部变量(不考虑捕获变量的复杂性)。这不像是在方法执行期间分配的空间。
- 恕我直言,您的密钥,请不要建议将作用域添加到交换盒块中。如果你需要一个新的范围为那块,可能是你做了太多的块。相反,我建议您将处理推送到函数调用。
- @伦道夫:我觉得这太笼统了。它可能只是三行或四行,但会影响两个或三个局部变量——这足以让重构为方法调用带来痛苦。
- 同意,我不止一次碰到这个问题,它是为了两到三行的处理逻辑…把它放在一个单独的方法里就是痛苦。
- 由于我的变量可以改变一个类型,取决于开关的小范围工作得很好。投票表决。
- 我尝试过这样做,但如果在子范围中声明变量以表示其他内容,则会产生错误。
- @爱德华德卡拉克:只有当你仍然在更高的范围内声明它。如果两种情况下都使用大括号,应该可以。
- case可以是多语句,必须以中断/返回结束,这与允许1个语句或新范围的if语句相反,这是什么原因?我建议,不要中断,重新使用if语句模式。它是如此…反模式…
- @万兰根:基本上是历史性的。switch声明有许多历史包袱。不过,C 8将有开关表达式,这将明显更好。
- @乔恩斯基特遗憾的是,他们在将模式添加到C_之前没有改变模式。我来检查一下C 8表达式。
因为它们的作用域在开关块上。C语言规范规定如下:
The scope of a local variable or constant declared in a switch block is the switch block.
变量在C编译器中共享作用域。然而,范围在CIL中并不以相同的方式存在。至于实际创建/初始化….NET内存模型允许编译器在遵循简单规则的情况下稍微移动读/写,除非变量被标记为volatile。
"在我的天啊…"
swicth是一个非常原始的程序实现,它在C本身的时代(甚至在C++之前)就已经存在了。
整个switch是一个块,用作包含GOTO:的作用域(因此每个case中的:)。如果你上了一些汇编类,那可能看起来很熟悉。
这就是为什么当与Enums结合时,switch的使用是最有用的,而不是在每一个类似case的break中使用。
1 2 3 4 5 6 7 8 9 10 11 12
| switch(mood)
{
case Mood.BORED:
case Mood.HAPPY:
drink(oBeer) // will drink if bored OR happy
break;
case Mood.SAD: // unnecessary but proofs a concept
default:
drink(oCoffee)
break;
} |
初始化发生在这种情况下,但是声明是在作用域的顶部有效地完成的。(伪代码)
1 2 3 4 5 6 7 8 9 10 11
| switch (Type)
{
string variable;
case Type.A:
variable ="x";
break;
case Type.B:
variable ="y";
break;
} |
- 我很小,确信这个密码不起作用
- @吉姆,是的,我知道代码不起作用——这就是为什么我把它称为"伪代码",但它是"有效"完成的。
- 不完全是这样。考虑一下,如果删除break,最终会得到如下结果:`` string variable="x";variable="y";``这是一个过程GOTO:,用于所有目的和目的。正确的代码应该类似于`` string myvar;switch(myvalue)case myenum.a:myvar="x";break;case myenum.b:myvar="y";break;```
- @感知-你所说的"正确"是什么意思?在您的示例中,myvar的范围将在开关块之外。我们的观点是,在这些骗局中,范围只是开关块。
- 这一点与人们普遍认为的相反,与if条款不同,switch条款是不含scope的条款。这是switch经常被视为"坏代码"(更像是未被理解)的主要原因之一,因此,声明括号内的内容仍然使其在全球范围内可用。msdn.microsoft.com/en-us/library/06tc147t.aspx