I was writing this code:
private static Expression<Func<Binding, bool>> ToExpression(BindingCriterion criterion)
{
switch (criterion.ChangeAction)
{
case BindingType.Inherited:
var action = (byte)ChangeAction.Inherit;
return (x => x.Action == action);
case BindingType.ExplicitValue:
var action = (byte)ChangeAction.SetValue;
return (x => x.Action == action);
default:
// TODO: Localize errors
throw new InvalidOperationException("Invalid criterion.");
}
}
And was surprised to find a compile error:
A local variable named 'action' is already defined in this scope
It was a pretty easy issue to resolve; just getting rid of the second var
did the trick.
Evidently variables declared in case
blocks have the scope of the parent switch
, but I'm curious as to why this is. Given that C# does not allow execution to fall through other cases (it requires break
, return
, throw
, or goto case
statements at the end of every case
block), it seems quite odd that it would allow variable declarations inside one case
to be used or conflict with variables in any other case
. In other words variables appear to fall through case
statements even though execution cannot. C# takes great pains to promote readability by prohibiting some constructs of other languages that are confusing or or easily abused. But this seems like it's just bound to cause confusion. Consider the following scenarios:
If were to change it to this:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: return (x => x.Action == action);
I get "Use of unassigned local variable 'action'". This is confusing because in every other construct in C# that I can think of
var action = ...
would initialize the variable, but here it simply declares it.If I were to swap the cases like this:
case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; return (x => x.Action == action); case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action);
I get "Cannot use local variable 'action' before it is declared". So the order of the case blocks appears to be important here in a way that's not entirely obvious -- Normally I could write these in any order I wish, but because the
var
must appear in the first block whereaction
is used, I have to tweakcase
blocks accordingly.If were to change it to this:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; goto case BindingType.Inherited;
Then I get no error, but in a sense, it looks like the variable is being assigned a value before it's declared.
(Although I can't think of any time you'd actually want to do this -- I didn't even knowgoto case
existed before today)
So my question is, why didn't the designers of C# give case
blocks their own local scope? Are there any historical or technical reasons for this?
action
variable before theswitch
statement, or put each case into its own braces, and you will get sensible behavior.switch
at all -- I'm just curious about the reasoning behind this design.switch
semantics from C / Java directly, and later made the decision to makecase
blocks more idiot proof by requiring jumps at the end, but they simply didn't feel the need to go one step further in idiot-proofing the identifier scope as well.