Error del compilador · error CS0163
El control no puede pasar de una etiqueta case a otra
Un case hizo su trabajo y luego… siguió hacia el siguiente case. En C y C++ eso es legal y causó décadas de bugs; en C# el compilador simplemente se niega. Cada case no vacío debe terminar en break;, return; o throw;.
Míralo ocurrir
int d = 1;
switch (d)
{
case 1:
Console.WriteLine("uno");
// sin break — el control "caería" en el case 2
case 2:
Console.WriteLine("dos");
break;
}
int d = 1;
switch (d)
{
case 1:
Console.WriteLine("uno");
break; // devuelve el control — listo
case 2:
Console.WriteLine("dos");
break;
}
Pero probablemente querías etiquetas apiladas
Lo que la gente suele querer cuando dice "fall-through" es varios valores compartiendo un cuerpo. Eso es legal — apila las etiquetas sin nada entre ellas:
void Clasificar(int dia)
{
switch (dia)
{
case 6:
case 7: // 6 y 7 comparten este cuerpo — sin código entre etiquetas
Console.WriteLine("fin de semana");
break;
default:
Console.WriteLine("día laborable");
break;
}
}
Clasificar(7);
Clasificar(3);
La regla es precisa: las etiquetas vacías pueden apilarse (no se cuela nada); una etiqueta con cualquier código debe cerrar su propio bloque.
Por qué C# es más estricto que C++ — y por qué es bueno
En C++, olvidar break ejecuta en silencio el código del case siguiente. El famoso bug goto fail de Apple tuvo exactamente esa forma. Los diseñadores de C# hicieron del break ausente un error de compilación, cambiando un poco de comodidad por la eliminación de toda una clase de bugs. Cuando te topas con CS0163, el compilador no está regañando — el lenguaje está cerrando una trampa de 50 años.
Finales que el compilador acepta
int Aplicar(char op, int a, int b)
{
switch (op)
{
case '+':
return a + b; // return cierra el case — sin break
case '*':
return a * b;
default:
throw new Exception("operador desconocido"); // throw también cierra
}
}
Console.WriteLine("resultado: " + Aplicar('*', 2, 4));
break sale del switch; return sale del método entero; throw sale de forma explosiva. Cualquiera de los tres satisface la regla — pero "llegar al final de un case" nunca lo hará.
Preguntas frecuentes
¿Cómo corrijo CS0163?
Cada case con cuerpo termina en break, return o throw. Para valores que comparten lógica, apila etiquetas sin sentencias entre ellas.
¿Por qué C# prohíbe el fall-through?
En C/C++ un break olvidado ejecuta el case siguiente en silencio — el bug goto fail de Apple. C# lo hace error de compilación; las etiquetas vacías apiladas siguen siendo legales.
Lista de comprobación
- Cada case con cuerpo termina en
break;,return …;othrow …;. - Varios valores, un cuerpo → apila etiquetas, cero sentencias entre ellas.
- No olvides
default:— también quiere subreak;. - Viniendo de C/C++/Java: sí, C# es realmente más estricto — a propósito.