我是否有理由错过case语句中的块不被视为块级声明空间?
当我尝试
时,我一直收到错误(已经声明了变量)case x:
var someVariable = 42;
break;
case y:
var someVariable = 40;
break;
但我能做到
case x:
try{var someVariable = 42;}catch{}
break;
case y:
try{var someVariable = 40;}catch{}
break;
如果C#允许通过语句,这是有道理的,但它没有,我想不出你可以在case语句中声明变量并在该块之外使用它的场景。
答案 0 :(得分:30)
更新:此问题被用作此博客文章的灵感来源;有关详细信息,请参阅。
http://ericlippert.com/2009/08/13/four-switch-oddities/
感谢有趣的问题。
在其他各种答案中存在许多混淆和错误陈述,其中没有一个真正解释了为什么这是非法的。我将尝试确定。
首先,要严格正确,“范围”是用来描述问题的错误词。巧合的是,我上周写了一篇关于“范围”错误使用的博客文章;这将在我的迭代器块系列之后发布,它将在整个7月份运行。
使用的正确术语是“声明空间”。声明空间是代码区域,其中不能声明两个不同的东西具有相同的名称。这里描述的场景表明一个开关部分没有定义声明空间,尽管交换机块确实存在。因为OP的两个声明属于同一个声明空间并且具有相同的名称,它们是非法的。
(是的,交换机块也定义范围,但这个事实与问题无关,因为问题是关于声明的合法性,而不是< strong>标识符查找的语义。)
一个合理的问题是“为什么这不合法?”一个合理的答案是“好吧,为什么要这样”?你可以用两种方式之一。这是合法的:
switch(y)
{
case 1: int x = 123; ... break;
case 2: int x = 456; ... break;
}
或这是合法的:
switch(y)
{
case 1: int x = 123; ... break;
case 2: x = 456; ... break;
}
但你不能两种方式。 C#的设计者选择第二种方式似乎是更自然的方式。
这个决定是在1999年7月7日做出的,就在十年前。当天笔记中的评论非常简短,只是简单地说明“一个开关案例不会创建自己的声明空间”,然后给出一些示例代码,显示哪些有效,哪些无效。
为了更多地了解设计师在这一天的想法,我不得不让很多人对他们十年前的想法感到不满 - 而且他们对最终的琐碎问题感到不满;我不打算这样做。
简而言之,没有特别令人信服的理由选择这样或那样的方式;两者都有优点。语言设计团队选择了一种方式,因为他们必须选择一种方式;他们选择的那个对我来说似乎很合理。
答案 1 :(得分:8)
啊 - 你没有摔倒,但是你可以使用goto跳转到另一个标记的case块。因此,块必须在同一范围内。
答案 2 :(得分:3)
你也可以这样做:
case x:
{var someVariable = 42;}
break;
case y:
{var someVariable = 40;}
break;
基本上大括号创建词法范围,因此没有大括号,someVariable会被加载到符号表中两次。我认为这种选择可能只是为了避免混淆,并可能避免增加符号表构建的复杂性。
答案 3 :(得分:2)
因为大小写不是块,所以没有花括号表示范围。由于缺乏更好的词语,案例就像标签一样。
最好在switch()
语句之外声明变量,然后再使用它。当然,在这种情况下,您将无法使用var
关键字,因为编译器将不知道要初始化的类型。
答案 4 :(得分:1)
从 C# 8.0 开始,您现在可以使用 switch expressions
<块引用>您使用 switch 表达式根据与输入表达式的模式匹配来评估候选表达式列表中的单个表达式
var someVariable = caseSwitch switch {
case x => 42,
case y => 40,
_ => throw new Exception("This is how to declare default")
};
答案 5 :(得分:0)
您可以将变量声明在switch语句的范围之外。
var someVariable;
switch();
case x:
someVariable = 42;
break;
case y:
someVariable = 40;
break;