español - switch case c# multiple condition
Múltiples casos en la instrucción switch (14)
¿Hay una manera de caer en múltiples declaraciones de casos sin indicar el case value:
repetidamente?
Sé que esto funciona:
switch (value)
{
case 1:
case 2:
case 3:
//do some stuff
break;
case 4:
case 5:
case 6:
//do some different stuff
break;
default:
//default stuff
break;
}
pero me gustaría hacer algo como esto:
switch (value)
{
case 1,2,3:
//Do Something
break;
case 4,5,6:
//Do Something
break;
default:
//Do the Default
break;
}
¿Estoy pensando en esta sintaxis de un idioma diferente o me estoy perdiendo algo?
.NET Framework 3.5 tiene rangos:
puede usarlo con "contiene" y la instrucción IF, ya que, como alguien dijo, la instrucción SWITCH usa el operador "==".
Aquí un ejemplo:
int c = 2;
if(Enumerable.Range(0,10).Contains(c))
DoThing();
else if(Enumerable.Range(11,20).Contains(c))
DoAnotherThing();
Pero creo que podemos divertirnos más: ya que no necesitará los valores de retorno y esta acción no toma parámetros, ¡puede usar acciones fácilmente!
public static void MySwitchWithEnumerable(int switchcase, int startNumber, int endNumber, Action action)
{
if(Enumerable.Range(startNumber, endNumber).Contains(switchcase))
action();
}
El viejo ejemplo con este nuevo método:
MySwitchWithEnumerable(c, 0, 10, DoThing);
MySwitchWithEnumerable(c, 10, 20, DoAnotherThing);
Ya que está pasando acciones, no valores, debe omitir el paréntesis, es muy importante. Si necesita una función con argumentos, simplemente cambie el tipo de Action
a Action<ParameterType>
. Si necesita valores de retorno, use Func<ParameterType, ReturnType>
.
En C # 3.0 no hay una aplicación parcial fácil para encapsular el hecho de que el parámetro de caso es el mismo, pero creas un pequeño método auxiliar (un poco detallado, aunque).
public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){
MySwitchWithEnumerable(3, startNumber, endNumber, action);
}
Aquí hay un ejemplo de cómo las nuevas declaraciones funcionales importadas son IMHO más poderosas y elegantes que la imperativa anterior.
@ Jennifer Owens: tienes toda la razón, el siguiente código no funcionará:
case 1 | 3 | 5:
//not working do something
La única manera de hacer esto es:
case 1: case 2: case 3:
// do something
break;
El código que está buscando funciona en Visual Basic, donde puede colocar fácilmente rangos ... en ninguna opción de cambio o, si no, en bloques convenientes, le sugiero, en un punto muy extremo, hacer .dll con Visual Basic e importar de nuevo a tu c # proyecto.
Nota: cambiar el equivalente en Visual Basic es seleccionar caso.
En realidad, tampoco me gusta el comando GOTO, pero está en los materiales oficiales de MS, aquí están todas las sintaxis permitidas.
Si se puede alcanzar el punto final de la lista de instrucciones de una sección de conmutador, se produce un error en tiempo de compilación. Esto se conoce como la regla de "no caer en". El ejemplo
switch (i) {
case 0:
CaseZero();
break;
case 1:
CaseOne();
break;
default:
CaseOthers();
break;
}
es válido porque ninguna sección de interruptor tiene un punto final alcanzable. A diferencia de C y C ++, la ejecución de una sección de conmutación no está permitida para "pasar" a la siguiente sección de conmutación, y el ejemplo
switch (i) {
case 0:
CaseZero();
case 1:
CaseZeroOrOne();
default:
CaseAny();
}
da como resultado un error en tiempo de compilación. Cuando la ejecución de una sección de conmutación va a ser seguida por la ejecución de otra sección de conmutación, se debe utilizar un caso goto explícito o una declaración predeterminada de goto:
switch (i) {
case 0:
CaseZero();
goto case 1;
case 1:
CaseZeroOrOne();
goto default;
default:
CaseAny();
break;
}
Se permiten múltiples etiquetas en una sección de conmutación. El ejemplo
switch (i) {
case 0:
CaseZero();
break;
case 1:
CaseOne();
break;
case 2:
default:
CaseTwo();
break;
}
Creo que en este caso particular, se puede usar el GOTO, en realidad es la única forma de lograrlo.
fuente: http://msdn.microsoft.com/en-us/library/aa664749%28v=vs.71%29.aspx
Esta sintaxis es de Visual Basic Select ... Case Statement :
Dim number As Integer = 8
Select Case number
Case 1 To 5
Debug.WriteLine("Between 1 and 5, inclusive")
'' The following is the only Case clause that evaluates to True.
Case 6, 7, 8
Debug.WriteLine("Between 6 and 8, inclusive")
Case Is < 1
Debug.WriteLine("Equal to 9 or 10")
Case Else
Debug.WriteLine("Not between 1 and 10, inclusive")
End Select
No puede utilizar esta sintaxis en C #. En su lugar, debe utilizar la sintaxis de su primer ejemplo.
No hay sintaxis en C ++ ni en C # para el segundo método que mencionó.
No hay nada malo con tu primer método. Sin embargo, si tiene rangos muy grandes, solo use una serie de sentencias if.
Otra opción sería utilizar una rutina. Si todos los casos del 1 al 3 ejecutan la misma lógica, envuelva esa lógica en una rutina y llámela para cada caso. Sé que esto realmente no elimina las declaraciones del caso, pero implementa un buen estilo y mantiene el mantenimiento al mínimo ...
[Editar] Se agregó implementación alternativa para que coincida con la pregunta original ... [/ Editar]
switch (x)
{
case 1:
DoSomething();
break;
case 2:
DoSomething();
break;
case 3:
DoSomething();
break;
...
}
private void DoSomething()
{
...
}
Alt
switch (x)
{
case 1:
case 2:
case 3:
DoSomething();
break;
...
}
private void DoSomething()
{
...
}
Para esto, usarías una instrucción goto. Como:
switch(value){
case 1:
goto case 3;
case 2:
goto case 3;
case 3:
DoCase123();
//This would work too, but I''m not sure if it''s slower
case 4:
goto case 5;
case 5:
goto case 6;
case 6:
goto case 7;
case 7:
DoCase4567();
}
Parece que se ha invertido una gran cantidad de trabajo en la búsqueda de formas de conseguir que una de las sintaxis menos utilizadas de C # se vea mejor o funcione mejor. Personalmente me parece que la declaración de cambio rara vez vale la pena usar. Recomiendo encarecidamente analizar qué datos está probando y los resultados finales que desea.
Digamos, por ejemplo, que desea probar rápidamente los valores en un rango conocido para ver si son números primos. Desea evitar que su código realice los cálculos inútiles y puede encontrar una lista de números primos en el rango que desea en línea. Podría usar una instrucción de cambio masivo para comparar cada valor con números primos conocidos.
O simplemente puede crear un mapa de matriz de números primos y obtener resultados inmediatos:
bool[] Primes = new bool[] {
false, false, true, true, false, true, false,
true, false, false, false, true, false, true,
false,false,false,true,false,true,false};
private void button1_Click(object sender, EventArgs e) {
int Value = Convert.ToInt32(textBox1.Text);
if ((Value >= 0) && (Value < Primes.Length)) {
bool IsPrime = Primes[Value];
textBox2.Text = IsPrime.ToString();
}
}
Tal vez quieras ver si un carácter en una cadena es hexadecimal. Podrías usar una declaración de cambio ungly y algo grande.
O puede usar expresiones regulares para probar el carácter o usar la función IndexOf para buscar el carácter en una cadena de letras hexadecimales conocidas:
private void textBox2_TextChanged(object sender, EventArgs e) {
try {
textBox1.Text = ("0123456789ABCDEFGabcdefg".IndexOf(textBox2.Text[0]) >= 0).ToString();
} catch {
}
}
Digamos que desea realizar una de 3 acciones diferentes en función de un valor que estará en el rango de 1 a 24. Le sugeriría que utilice un conjunto de declaraciones IF. Y si eso se volvió demasiado complejo (o los números eran más grandes, como 5 acciones diferentes dependiendo de un valor en el rango de 1 a 90), use una enumeración para definir las acciones y crear un mapa matricial de las enumeraciones. El valor se usaría para indexar en el mapa de la matriz y obtener la enumeración de la acción que desea. Luego use un pequeño conjunto de declaraciones IF o una instrucción de cambio muy simple para procesar el valor de enumeración resultante.
Además, lo bueno de un mapa de matriz que convierte un rango de valores en acciones es que se puede cambiar fácilmente mediante un código. Con el código cableado no puede cambiar fácilmente el comportamiento en tiempo de ejecución, pero con un mapa de matriz es fácil.
Puedes dejar de lado la nueva línea que te da:
case 1: case 2: case 3:
break;
Pero considero ese mal estilo.
Si tiene una gran cantidad de cadenas (o cualquier otro tipo), todas hacen lo mismo, recomiendo el uso de una lista de cadenas combinada con la propiedad string.Contains.
Así que si tienes una gran instrucción de cambio como esta:
switch (stringValue)
{
case "cat":
case "dog":
case "string3":
...
case "+1000 more string": //Too many string to write a case for all!
//Do something;
case "a lonely case"
//Do something else;
.
.
.
}
Es posible que desee reemplazarlo con una instrucción if como esta:
//Define all the similar "case" string in a List
List<string> listString = new List<string>(){ "cat", "dog", "string3", "+1000 more string"};
//Use string.Contains to find what you are looking for
if (listString.Contains(stringValue))
{
//Do something;
}
else
{
//Then go back to a switch statement inside the else for the remaining cases if you really need to
}
Esta escala bien para cualquier número de cadenas.
Supongo que esto ya ha sido respondido. Sin embargo, creo que aún puede combinar ambas opciones de una manera sintácticamente mejor haciendo:
switch (value)
{
case 1: case 2: case 3:
// Do Something
break;
case 4: case 5: case 6:
// Do Something
break;
default:
// Do Something
break;
}
Un poco tarde para la pregunta original, pero estoy publicando esta respuesta con la esperanza de que alguien que use una versión más reciente ( C # 7, disponible de manera predeterminada en Visual Studio 2017 / .NET Framework 4.6.2 ), la encuentre útil.
En C # 7, el cambio basado en rango ahora es posible con la declaración de cambio y ayudaría con el problema del OP.
Ejemplo:
int i = 5;
switch (i)
{
case int n when (n >= 7):
Console.WriteLine($"I am 7 or above: {n}");
break;
case int n when (n >= 4 && n <= 6 ):
Console.WriteLine($"I am between 4 and 6: {n}");
break;
case int n when (n <= 3):
Console.WriteLine($"I am 3 or less: {n}");
break;
}
// Output: I am between 4 and 6: 5
Notas:
- Los paréntesis
(
y)
no se requieren en la condición dewhen
, pero se usan en este ejemplo para resaltar las comparaciones. -
var
también se puede utilizar en lugar deint
. Por ejemplo:case var n when n >= 7:
Una faceta menos conocida del switch en C # es que se basa en el operador = y como puede anularse, podría tener algo como esto:
string s = foo();
switch (s) {
case "abc": /*...*/ break;
case "def": /*...*/ break;
}
gcc implementa una extensión al lenguaje C para admitir rangos secuenciales:
switch (value)
{
case 1...3:
//Do Something
break;
case 4...6:
//Do Something
break;
default:
//Do the Default
break;
}
Edición : Acabo de notar la etiqueta C # en la pregunta, así que, presumiblemente, una respuesta de gcc no ayuda.