Múltiples casos en la instrucción switch


¿Hay una manera de caer a través de múltiples declaraciones de casos sin declarar 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;
}

¿Es esta sintaxis en la que estoy pensando de un lenguaje diferente, o me estoy perdiendo algo?

Author: Bugs, 2008-09-16

14 answers

No hay sintaxis en C++ ni en C# para el segundo método que mencionaste.

No hay nada malo con tu primer método. Sin embargo, si tiene rangos muy grandes, simplemente use una serie de sentencias if.

 256
Author: Brian R. Bondy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 02:30:06

Supongo que esto ya ha sido contestado. Sin embargo, creo que aún puedes mezclar 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;
}
 617
Author: Carlos Quintanilla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-03 16:01:14

Esta sintaxis es de la selección de Visual Basic ...Declaración del caso :

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 usar esta sintaxis en C#. En su lugar, debe usar la sintaxis de su primer ejemplo.

 63
Author: Neal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-08 12:27:57

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 available disponible por defecto en Visual Studio 2017/. NET Framework 4.6.2), lo encuentre útil.

En C# 7, la conmutación basada en rango ahora es posible con la instrucción switch 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 son necesarios en la condición when, pero se utilizan en este ejemplo para resaltar la(s) comparación (es).
  • var también podrá utilizarse en lugar de int. Por ejemplo: case var n when n >= 7:.
 35
Author: Steve G.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-22 17:01:53

Puedes omitir la nueva línea que te da:

case 1: case 2: case 3:
   break;

Pero considero que ese estilo es malo.

 28
Author: Allan Wind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-26 15:11:03

. NET Framework 3.5 tiene rangos:

Enumerable.Rango de MSDN

Puede usarlo con "contains" 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ás los valores devueltos y esta acción no toma parámetros, ¡puedes 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 antiguo ejemplo con este nuevo método:

MySwitchWithEnumerable(c, 0, 10, DoThing);
MySwitchWithEnumerable(c, 10, 20, DoAnotherThing);

Puesto que están 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 devueltos, utilice Func<ParameterType, ReturnType>.

En C# 3.0 no hay fácil Aplicación parcial para encapsular el hecho de que el parámetro case es el mismo, pero se crea un pequeño método auxiliar (un poco detallado, tho).

public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){ 
    MySwitchWithEnumerable(3, startNumber, endNumber, action); 
}

Aquí un ejemplo de cómo nueva declaración importada funcional son IMHO más potente y elegante que el viejo imperativo.

 17
Author: Luca Molteni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-30 00:37:06

@ 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ás buscando funciona en visual basic donde puedes poner rangos fácilmente... en ninguna opción de interruptor o si los bloques de lo contrario conveniente, yo sugeriría, en el punto muy extremo, hacer .dll con visual basic e importar de nuevo a su proyecto de c#.

Nota: el equivalente del conmutador en visual basic es select case.

 8
Author: none,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 13:34:54

Otra opción sería usar una rutina. Si todos los casos 1-3 ejecutan la misma lógica, envuelva esa lógica en una rutina y llámela para cada caso. Sé que esto en realidad no se deshace de las declaraciones de casos, pero implementa un buen estilo y mantiene el mantenimiento al mínimo.....

[Editar] Se agregó una implementación alternativa para que coincida con la pregunta original...[/Edit]

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()
{
   ...
}
 6
Author: Dr8k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 03:30:13

Una faceta menos conocida de switch en C # es que se basa en el operador = y como puede ser anulado, podría tener algo como esto:


string s = foo();

switch (s) {
  case "abc": /*...*/ break;
  case "def": /*...*/ break;
}
 5
Author: Leonardo Constantino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 02:16:25

Gcc implementa una extensión al lenguaje C para soportar rangos secuenciales:

switch (value)
{
   case 1...3:
      //Do Something
      break;
   case 4...6:
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

Editar: Acabo de notar la etiqueta C# en la pregunta, por lo que presumiblemente una respuesta gcc no ayuda.

 5
Author: DGentry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 02:59:52

En realidad no me gusta el comando GOTO también, pero está en materiales oficiales de MS, aquí están todas las sintaxis permitidas.

Si el punto final de la lista de instrucciones de una sección switch es accesible, se produce un error en tiempo de compilación. Esto se conoce como la regla de "no caer a través". El ejemplo

switch (i) {
case 0:
   CaseZero();
   break;
case 1:
   CaseOne();
   break;
default:
   CaseOthers();
   break;
}

Es válido porque ninguna sección de switch tiene un punto final accesible. A diferencia de C y C++, la ejecución de una sección de switch no está permitida para "caerse" a la siguiente sección de switch, y ejemplo

switch (i) {
case 0:
   CaseZero();
case 1:
   CaseZeroOrOne();
default:
   CaseAny();
}

Resulta en un error en tiempo de compilación. Cuando la ejecución de una sección de switch va a ser seguida por la ejecución de otra sección de switch, se debe usar una sentencia explícita goto case o goto default:

switch (i) {
case 0:
   CaseZero();
   goto case 1;
case 1:
   CaseZeroOrOne();
   goto default;
default:
   CaseAny();
   break;
}

Se permiten varias 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, el GOTO se puede utilizar, en realidad es la única manera de caer.

Fuente: http://msdn.microsoft.com/en-us/library/aa664749%28v=vs.71%29.aspx

 3
Author: Jiří Herník,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-08 08:21:39

Parece que se ha puesto mucho trabajo en encontrar formas de conseguir que una de las sintaxis de C# menos utilizadas se vea mejor o funcione mejor. Personalmente me parece que la declaración switch rara vez vale la pena usar. Le sugeriría encarecidamente analizar qué datos está probando y los resultados finales que desea.

Digamos, por ejemplo, que desea probar rápidamente valores en un rango conocido para ver si son números primos. Usted quiere evitar que su código haga los cálculos derrochadores y usted puede encontrar una lista de primos en el rango que desee en línea. Podría usar una sentencia de cambio masivo para comparar cada valor con números primos conocidos.

O simplemente podría crear un mapa de matrices de 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. Usted podría utilizar una declaración de interruptor ungly y algo grande.

O puede usar expresiones regulares para probar el char o usar la función indexOf para buscar el char 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 hacer una de 3 acciones diferentes dependiendo de un valor que será el rango de 1 a 24. Yo sugeriría el uso de 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 de matriz de las enumeraciones. El valor entonces sería utilizado para indexar en el mapa de matriz y obtener el enum de la acción que desea. A continuación, utilice un pequeño conjunto de sentencias IF o una sentencia switch 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 por 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.

 2
Author: Darin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-23 06:25:00

Si usted tiene una cantidad muy grande de cadena (o cualquier otro tipo) Caso todos haciendo lo mismo, recomiendo el uso de una lista de cadena combinada con la cadena.Contiene la propiedad.

Así que si tienes una gran sentencia switch 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 sentencia 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 cadena de caso.

 1
Author: Maxter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-29 16:00:21

Para esto, usarías una declaración goto. Tales 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();
    }
 -3
Author: scone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-09 22:41:49