Kevin Kevin - 3 months ago 11
C# Question

Case Statement Block Level Declaration Space in C#

Is there a reason I am missing that a block within a case statement isn't considered a block level declaration space?

I keep getting an error (variable has already been declared) when I try

case x:
var someVariable = 42;
break;
case y:
var someVariable = 40;
break;


but I can do

case x:
try{var someVariable = 42;}catch{}
break;
case y:
try{var someVariable = 40;}catch{}
break;


If C# allowed fall through statements, that would make sense, but it doesn't, and I can't think of a scenario where you can declare a variable in a case statement and use it outside of that block.

Answer

UPDATE: This question was used as the inspiration for this blog post; see it for further details.

http://ericlippert.com/2009/08/13/four-switch-oddities/

Thanks for the interesting question.


There are a number of confusions and mis-statements in the various other answers, none of which actually explain why this is illegal. I shall attempt to be definitive.

First off, to be strictly correct, "scope" is the wrong word to use to describe the problem. Coincidentally, I wrote a blog post last week about this exact mis-use of "scope"; that will be published after my series on iterator blocks, which will run throughout July.

The correct term to use is "declaration space". A declaration space is a region of code in which no two different things may be declared to have the same name. The scenario described here is symptomatic of the fact that a switch section does not define a declaration space, though a switch block does. Since the OP's two declarations are in the same declaration space and have the same name, they are illegal.

(Yes, the switch block also defines a scope but that fact is not relevant to the question because the question is about the legality of a declaration, not the semantics of an identifier lookup.)

A reasonable question is "why is this not legal?" A reasonable answer is "well, why should it be"? You can have it one of two ways. Either this is legal:

switch(y)
{
case 1:  int x = 123; ... break;
case 2:  int x = 456; ... break;
}

or this is legal:

switch(y)
{
case 1:  int x = 123; ... break;
case 2:  x = 456; ... break;
}

but you can't have it both ways. The designers of C# chose the second way as seeming to be the more natural way to do it.

This decision was made on July 7th, 1999, just shy of ten years ago. The comments in the notes from that day are extremely brief, simply stating "A switch-case does not create its own declaration space" and then giving some sample code that shows what works and what does not.

To find out more about what was in the designers minds on this particular day, I'd have to bug a lot of people about what they were thinking ten years ago -- and bug them about what is ultimately a trivial issue; I'm not going to do that.

In short, there is no particularly compelling reason to choose one way or the other; both have merits. The language design team chose one way because they had to pick one; the one they picked seems reasonable to me.