Como parece saber, poner dos cadenas en minúsculas y compararlas no es lo mismo que hacer una comparación de caso omiso. Hay muchas razones para esto. Por ejemplo, el estándar Unicode permite codificar texto con signos diacríticos de varias formas. Algunos caracteres incluyen tanto el carácter base como el diacrítico en un solo punto de código. Estos caracteres también pueden representarse como el carácter base seguido de un carácter diacrítico combinado. Estas dos representaciones son iguales para todos los propósitos, y las comparaciones de cadenas con reconocimiento cultural en .NET Framework las identificarán correctamente como iguales, ya sea con CurrentCulture o InvariantCulture (con o sin IgnoreCase). Una comparación ordinal, por otro lado, los considerará incorrectamente como desiguales.
Desafortunadamente, switch
no hace nada más que una comparación ordinal. Una comparación ordinal está bien para ciertos tipos de aplicaciones, como analizar un archivo ASCII con códigos rígidamente definidos, pero la comparación de cadenas ordinales es incorrecta para la mayoría de los otros usos.
Lo que he hecho en el pasado para obtener el comportamiento correcto es simplemente simular mi propia declaración de cambio. Hay muchas formas de hacer esto. Una forma sería crear un List<T>
par de cadenas de casos y delegados. Se puede buscar en la lista utilizando la comparación de cadenas adecuada. Cuando se encuentra la coincidencia, se puede invocar al delegado asociado.
Otra opción es hacer la cadena obvia de if
declaraciones. Esto generalmente resulta no ser tan malo como parece, ya que la estructura es muy regular.
Lo bueno de esto es que realmente no hay ninguna penalización en el rendimiento al simular la funcionalidad de su propio interruptor cuando se compara con cadenas. El sistema no va a hacer una tabla de salto O (1) como puede hacerlo con números enteros, por lo que comparará cada cadena una a la vez de todos modos.
Si hay muchos casos para comparar y el rendimiento es un problema, entonces la List<T>
opción descrita anteriormente podría reemplazarse con un diccionario ordenado o una tabla hash. Entonces, el rendimiento puede igualar o superar potencialmente la opción de declaración de cambio.
A continuación se muestra un ejemplo de la lista de delegados:
delegate void CustomSwitchDestination();
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList;
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound);
void CustomSwitch(string value)
{
foreach (var switchOption in customSwitchList)
if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase))
{
switchOption.Value.Invoke();
return;
}
defaultSwitchDestination.Invoke();
}
Por supuesto, probablemente querrá agregar algunos parámetros estándar y posiblemente un tipo de retorno al delegado CustomSwitchDestination. ¡Y querrás hacer mejores nombres!
Si el comportamiento de cada uno de sus casos no es susceptible de delegar la invocación de esta manera, por ejemplo, si son necesarios diferentes parámetros, entonces está atascado con if
declaraciones encadenadas . También he hecho esto algunas veces.
if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase))
{
s = "window";
}
else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase))
{
s = "really big window";
}
else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase))
{
s = "broken window";
}
ToUpperInvariant()
oToLowerInvariant()
? Además, no está comparando dos cadenas desconocidas , está comparando una cadena desconocida con una cadena conocida. Por lo tanto, siempre que sepa cómo codificar la representación adecuada en mayúsculas o minúsculas, el bloque de interruptores debería funcionar bien.