2010-05-30 16 views
18

Estoy empezando aprendiendo C# y me he quedado atrapado en algo muy básico.¿Es imposible usar rangos decimales en un interruptor en C#?

Para mi primera "aplicación" pensé que iría por algo simple, así que decidí usar una calculadora de IMC.

El IMC se calcula en un tipo de decimal que ahora estoy tratando de usar en una declaración de cambio, pero aparentemente decimal no se puede usar en un interruptor?

¿Cuál sería la solución C# para esto:

  decimal bmi = calculate_bmi(h, w); 

      switch (bmi) { 
       case < 18.5: 
        bmi_description = "underweight."; 
        break; 
       case > 25: 
        bmi_description = "overweight"; 
       case > 30: 
        bmi_description = "very overweight"; 
       case > 40: 
        bmi_description = "extreme overweight"; 
        break; 
      } 
+0

Irony: http://stackoverflow.com/questions/2875533/what-features-do-you-want-to-see-in-net-5-c-5/2876114#2876114 – Dykam

Respuesta

14

La declaración switch sólo admite integral types (enumeraciones no se muestran, pero se pueden utilizar con switch declaraciones porque están respaldados por una de tipo integral) (cadenas también están soportados como ha señalado Changeling - ver el comentario Para mayor referencia) y la igualdad comparaciones con valores constantes. Por lo tanto, debe usar algunas declaraciones if.

if (bmi < 18.5M) 
{ 
    bmi_description = "underweight."; 
} 
else if (bmi <= 25) 
{ 
    // You missed the 'normal' case in your example. 
} 
else if (bmi <= 30) 
{ 
    bmi_description = "overweight"; 
} 
else if (bmi <= 40) 
{ 
    bmi_description = "very overweight"; 
} 
else 
{ 
    bmi_description = "extreme overweight"; 
} 

Por cierto su sentencia switch es un poco weired porque se cambia de al menos mayor que el uso y la caída a través sin interrupciones. Creo que uno debe usar solo un tipo de comparación para hacer que el código sea más fácil de entender o reordenar los cheques y no utilizar el fall-through.

if (bmi < 18.5M) 
{ 
    bmi_description = "underweight."; 
} 
else if (bmi > 40) 
{ 
    bmi_description = "extreme overweight"; 
} 
else if (bmi > 30) 
{ 
    bmi_description = "very overweight"; 
} 
else if (bmi > 25) 
{ 
    bmi_description = "overweight"; 
} 
else 
{ 
    // You missed the 'normal' case in your example. 
} 
+0

Esto es un poco inexacto. El operador de cambio también puede usar cadenas. Consulte aquí: http://msdn.microsoft.com/en-us/library/06tc147t%28VS.71%29.aspx –

+1

Gracias por señalarlo; actualizado la respuesta. –

+0

¡Gracias por la ayuda! La M después del decimal 18.5 era lo que faltaba en las otras soluciones, así que esta lo resolvió para mí. ¿Hay algún "nombre" para lo que hace M, para que pueda leer más sobre él? – phobia

9

Eso no es posible con switch declaraciones en C#.
La razón es porque cada enunciado de caso requiere una expresión constante después de él.

Además, cada valor está permitido solo una vez y el tipo de expresión debe coincidir con el tipo en su switch. En su caso, ese no es el caso porque usted quería tener bool tipo case declaraciones, pero un decimal en su switch.

Considere refactorización utilizando una función de ayuda en su lugar:

//... 
decimal bmi = calculate_bmi(h, w); 
string bmi_description = get_description_for_bmi(bmi); 
//... 

string get_description_for_bmi(decimal bmi) 
{ 
    string desc; 
    if(bmi < 18.5m) 
     desc = "underweight"; 
    else if(bmi <= 25) 
     desc = "average";//You forgot this one btw 
    else if(bmi <= 30) 
     desc = "overweight"; 
    else if(bmi <= 40) 
     desc = "very overweight";  
    else 
     desc = "extreme overweight"; 

    return desc; 
} 

Más información:

No sólo son valores de rango, pero no se admiten expresiones no constantes tampoco están permitidos.

Aquí es un ejemplo de algo que no es posible:

bool b = true; 
bool y = false; 
switch (b) 
{ 
    case true: 
     break; 
    case y: 
     break; 
} 

Sin embargo esto es posible:

bool b = true; 
const bool y = false; 
switch (b) 
{ 
    case true: 
     break; 
    case y: 
     break; 
} 
+0

Puedes hacerlo más simple : no es necesario que compruebe 'bmi> 18.5', ya que está en' else'. Lo mismo ocurre con las siguientes pruebas. 'if (bmi <= 18.5) ... else if (bmi <= 25) ... else if (bmi <= 30) ...' –

+0

@Thomas: True thanks, fixed. –

+0

Para * exactamente * hacer coincidir el comportamiento del código de la pregunta, debe ser <18.5 en lugar de <= 18.5. –

0

También es posible usar algún tipo de colección que almacena los valores de corte y descripciones. (No soy un experto en C# ... tal vez Dictionary<decimal,string>?) Itere a través de él para encontrar el último que sea menor que su bmi, y devuelva su etiqueta correspondiente.

+0

Sí, esto suena como una buena solución ... debería ser capaz de iterar sobre la clave o el valor con bastante facilidad utilizando una colección genérica como Dictionary. Si se siente lo suficientemente seguro como para usar un genérico, intente usar un enumerador como una enumeración y active los valores constantes que posee actualmente una variable enum. – IbrarMumtaz

0

La palabra clave del interruptor funciona bien con decimales. Es < y> que te están causando problemas.

+0

El interruptor no * coopera * con decimal (además de esto es nuevo en 4.0). –

1

Su sección de lectura adicional,

interruptores sólo pueden ser operados con los valores o los casos en que el valor de entrada es un valor constante que el conmutador puede mirar hacia arriba como un índice y ejecutar el código adjunto definido dentro de una caja o case point o case, cualquier cosa que se pueda usar indistintamente.

Cambie y a true en el primer ejemplo y el interruptor debería funcionar en 'b'.

El segundo ejemplo funciona porque el segundo caso está activando un valor constante o 'const'. Por lo tanto, cumple con los criterios básicos o lo que necesita un interruptor. Aunque muchos aquí definitivamente te dirían que no codifiques así. Active un valor constante simple y asegúrese de que su interruptor atienda con precisión cada uno de los diferentes valores que podría tener la variable suministrada.

Pruebe usar una enumeración para hacer que su código coincida con las prácticas de codificación estándar de .Net. Este comentario también entra en la línea de asegurarse de no tomar ningún mal hábito si quiere hacer una carrera de esto ???

RECUERDA: que puedes usar una enumeración y configurarla para usar valores decimales ya que el decimal es un tipo de valor, por lo que cumple los criterios de lo que requiere una enumeración. Como enum se define en el marco .Net como un tipo de valor, solo los tipos de valores como los tipos basados ​​en números se pueden configurar para crear un tipo de enumeración en las clases de código personalizado. Simplemente adjunte cada valor con un nombre o algún tipo como lo usó anteriormente, como sobrepeso, etc. y asegúrese de que cada entrada en la enumeración tenga un orden lógico. es decir, las entradas en términos de sus valores decimales tienen una definición clara de subir o bajar. Una vez configurada su enumeración, cree una variable del tipo de enumeración que acaba de crear y luego suministre esta variable a su conmutador.

Diviértete aprendiendo.

Cuestiones relacionadas