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 me sorprendió encontrar un error de compilación:
Una variable local llamada 'acción' ya está definida en este ámbito
Era un problema bastante fácil de resolver; solo deshacerme del segundo varhizo el truco.
Evidentemente, las variables declaradas en casebloques tienen el alcance del padre switch, pero tengo curiosidad de por qué esto es así. Dado que C # no permite la ejecución de caer a través de otros casos (que requiere break , return, throw, o goto casedeclaraciones al final de cada casebloque), parece bastante extraño que permitiría a las declaraciones de variables dentro de una casea usarse o conflicto con las variables en cualquier otro case. En otras palabras, las variables parecen caer a través de las casedeclaraciones aunque la ejecución no puede. C # se esfuerza mucho para promover la legibilidad al prohibir algunas construcciones de otros lenguajes que son confusos o de abuso fácil. 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 no asignada 'acción' ". Esto es confuso porque en cualquier otra construcción en C # que se me ocurra
var action = ...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 se puede usar la variable local 'acción' antes de que se declare ". Entonces, 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 debido a que
vardebe aparecer en el primer bloque dondeactionse usa, tengo que ajustar loscasebloques 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 a la variable se le está asignando un valor antes de que se declare.
(Aunque no puedo pensar en ningún momento en el que realmente quieras hacer esto, ni siquiera sabía quegoto caseexistía antes de hoy)
Entonces mi pregunta es, ¿por qué los diseñadores de C # no le dieron a los casebloques su propio alcance local? ¿Hay alguna razón histórica o técnica para esto?
switchsolo tengo curiosidad sobre el razonamiento detrás de este diseño.
breakno sea posible en C #.
actionvariable antes de laswitchdeclaración, o ponga cada caso en sus propios corchetes, y obtendrá un comportamiento sensato.