Estaba escribiendo este código:
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.");
}
}
Y se sorprendió al encontrar un error de compilación:
Una variable local llamada 'acción' ya está definida en este ámbito
Fue un problema bastante fácil de resolver; Simplemente deshacerse del segundo var
hizo el truco.
Evidentemente, las variables declaradas en bloques case
tienen el alcance del switch
padre, pero tengo curiosidad por saber por qué esto es así. Dado que C # no permite que la ejecución caiga en otros casos ( requiere break
, return
, throw
, o goto case
de las declaraciones al final de cada bloque case
), parece bastante extraño que permita que se utilicen declaraciones de variables dentro de un case
o que entren en conflicto con las variables en cualquier otro %código%. En otras palabras, las variables parecen caer en case
de las declaraciones, aunque la ejecución no puede. C # hace grandes esfuerzos para promover la legibilidad al prohibir algunas construcciones de otros lenguajes que son confusos o que se abusan fácilmente. Pero esto parece que está destinado a causar confusión. Considere los siguientes escenarios:
-
Si fuera a cambiarlo a esto:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: return (x => x.Action == action);
Obtengo " Uso de la variable local sin asignar 'acción' ". Esto es confuso porque en cualquier otra construcción en C # que se me ocurra,
case
inicializaría la variable, pero aquí simplemente la declara. -
Si tuviera que cambiar los casos de esta manera:
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);
Obtengo " No puedo usar la variable 'acción' local antes de que se declare ". Así que el orden de los bloques de casos parece ser importante aquí de una manera que no es del todo obvia. Normalmente, podría escribirlos en el orden que desee, pero porque
var action = ...
debe aparecer en el primer bloque donde se usavar
, Tengo que modificaraction
bloques en consecuencia. -
Si fuera a cambiarlo a esto:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; goto case BindingType.Inherited;
Entonces no obtengo ningún error, pero en cierto sentido, parece que se asigna un valor a la variable antes de que se declare.
(Aunque no puedo pensar en ningún el momento en el que realmente desea hacer esto (ni siquiera sabía quecase
existía antes de hoy)
Entonces, mi pregunta es, ¿por qué los diseñadores de C # give goto case
bloquean su alcance local? ¿Hay razones históricas o técnicas para esto?