Si j’ai une déclaration de casse où l’object dans le commutateur est de la chaîne, est-il possible de faire de toute façon ignorerCase compare?
J’ai par exemple:
ssortingng s = "house"; switch (s) { case "houSe": s = "window"; }
Va obtenir la valeur “window”. Comment substituer l’instruction switch-case pour comparer les chaînes en utilisant ignoreCase?
Comme vous semblez le savoir, la mise en minuscules de deux chaînes et leur comparaison ne sont pas les mêmes que pour une comparaison de cas ignorés. Il y a beaucoup de raisons à cela. Par exemple, la norme Unicode permet de coder le texte avec des signes diacritiques de plusieurs manières. Certains caractères incluent à la fois le caractère de base et le signe diacritique dans un seul sharepoint code. Ces caractères peuvent également être représentés par le caractère de base suivi d’un caractère diacritique de combinaison. Ces deux représentations sont égales à toutes fins et les comparaisons de chaînes tenant compte de la culture dans le .NET Framework les identifient correctement comme étant égales, avec CurrentCulture ou InvariantCulture (avec ou sans IgnoreCase). Une comparaison ordinale, par contre, les considérera à tort comme inégale.
Malheureusement, switch
ne fait rien d’autre qu’une comparaison ordinale. Une comparaison ordinale convient à certains types d’applications, comme l’parsing d’un fichier ASCII avec des codes définis de manière rigide, mais la comparaison des chaînes ordinales est incorrecte pour la plupart des autres utilisations.
Ce que j’ai fait dans le passé pour obtenir le comportement correct, c’est de simuler ma propre déclaration de changement. Il y a plusieurs manières de faire ça. Une façon serait de créer une List
de paires de chaînes de cas et de delegates. La liste peut être recherchée en utilisant la comparaison de chaîne appropriée. Lorsque la correspondance est trouvée, le délégué associé peut être appelé.
Une autre option consiste à faire la chaîne évidente des instructions if
. Cela s’avère généralement pas aussi grave que cela en a l’air, car la structure est très régulière.
Ce qui est génial à ce sujet, c’est qu’il n’ya pas vraiment de pénalité en termes de performances lors de la comparaison de vos propres fonctionnalités de commutateur par rapport aux chaînes. Le système ne va pas créer un tableau de sauts O (1) comme il peut le faire avec les entiers. Il faudra donc comparer chaque chaîne une à la fois.
S’il y a beaucoup de cas à comparer et que les performances posent problème, alors l’option List
décrite ci-dessus pourrait être remplacée par un dictionnaire ou une table de hachage sortingés. Ensuite, la performance peut éventuellement correspondre ou dépasser l’option d’instruction switch.
Voici un exemple de la liste des delegates:
delegate void CustomSwitchDestination(); List> customSwitchList; CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound); void CustomSwitch(ssortingng value) { foreach (var switchOption in customSwitchList) if (switchOption.Key.Equals(value, SsortingngComparison.InvariantCultureIgnoreCase)) { switchOption.Value.Invoke(); return; } defaultSwitchDestination.Invoke(); }
Bien sûr, vous voudrez probablement append des parameters standard et éventuellement un type de retour au délégué CustomSwitchDestination. Et vous voudrez faire de meilleurs noms!
Si le comportement de chacun de vos cas ne permet pas de déléguer l’invocation de cette manière, par exemple si des parameters différents sont nécessaires, vous êtes bloqué avec les statuts chaînés. Je l’ai aussi fait plusieurs fois.
if (s.Equals("house", SsortingngComparison.InvariantCultureIgnoreCase)) { s = "window"; } else if (s.Equals("business", SsortingngComparison.InvariantCultureIgnoreCase)) { s = "really big window"; } else if (s.Equals("school", SsortingngComparison.InvariantCultureIgnoreCase)) { s = "broken window"; }
Une approche plus simple consiste simplement à mettre une chaîne en minuscule avant d’entrer dans l’instruction switch et de réduire les cas.
En fait, la partie supérieure est un peu meilleure du sharepoint vue de la performance extrême en nanosecondes, mais moins naturelle à regarder.
Par exemple:
ssortingng s = "house"; switch (s.ToLower()) { case "house": s = "window"; break; }
Dans certains cas, il peut être judicieux d’utiliser une énumération. Donc, d’abord parsingr l’énumération (avec l’indicateur ignoreCase true) et avoir un commutateur sur l’énumération.
SampleEnum Result; bool Success = SampleEnum.TryParse(inputText, true, out Result); if(!Success){ //value was not in the enum values }else{ switch (Result) { case SampleEnum.Value1: break; case SampleEnum.Value2: break; default: //do default behaviour break; } }
Désolé pour ce nouveau message à une ancienne question, mais il existe une nouvelle option pour résoudre ce problème en utilisant C # 7 (VS 2017).
C # 7 offre maintenant une “correspondance de modèle” et peut être utilisé pour résoudre ce problème:
ssortingng houseName = "house"; // value to be tested, ignoring case ssortingng windowName; // switch block will set value here switch (true) { case bool b when houseName.Equals("MyHouse", SsortingngComparison.InvariantCultureIgnoreCase): windowName = "MyWindow"; break; case bool b when houseName.Equals("YourHouse", SsortingngComparison.InvariantCultureIgnoreCase): windowName = "YourWindow"; break; case bool b when houseName.Equals("House", SsortingngComparison.InvariantCultureIgnoreCase): windowName = "Window"; break; default: windowName = null; break; }
Cette solution traite également du problème mentionné dans la réponse de @Jeffrey L Whitledge: la comparaison insensible à la casse des chaînes n’est pas la même chose que la comparaison de deux chaînes en bas de casse.
En passant, il y avait un article intéressant en février 2017 dans Visual Studio Magazine décrivant la correspondance de modèle et comment il peut être utilisé dans les blocs de cas. Jetez un coup d’oeil: pattern matching dans les blocs de cas C # 7.0
MODIFIER
À la lumière de la réponse de @ LewisM, il est important de souligner que la déclaration de switch
a un nouveau comportement intéressant. En d’autres termes, si votre déclaration de case
contient une déclaration de variable, la valeur spécifiée dans la partie switch
est copiée dans la variable déclarée dans le case
. Dans l’exemple suivant, la valeur true
est copiée dans la variable locale b
. De plus, la variable b
est inutilisée et n’existe que pour que la clause when
de l’instruction case
puisse exister:
switch(true) { case bool b when houseName.Equals("X", SsortingngComparison.InvariantCultureIgnoreCase): windowName = "X-Window";): break; }
Comme @LewisM le fait remarquer, cela peut être bénéfique – cet avantage étant que la chose comparée se trouve réellement dans l’instruction switch
, comme c’est le cas avec l’utilisation classique de l’instruction switch
. En outre, les valeurs temporaires déclarées dans l’instruction de case
peuvent empêcher des modifications indésirables ou involontaires de la valeur d’origine:
switch(houseName) { case ssortingng hn when hn.Equals("X", SsortingngComparison.InvariantCultureIgnoreCase): windowName = "X-Window"; break; }
Une façon possible serait d’utiliser un dictionnaire de casse avec un délégué d’action.
ssortingng s = null; var dic = new Dictionary(SsortingngComparer.CurrentCultureIgnoreCase) { {"house", () => s = "window"}, {"house2", () => s = "window2"} }; dic["HouSe"]();
Une extension de la réponse de @STLDeveloperA. Une nouvelle façon d’évaluer les instructions sans plusieurs instructions if à partir de c # 7 consiste à utiliser l’instruction Switch de correspondance de modèle, similaire à la façon dont @STLDeveloper modifie de cette façon la variable en cours de commutation.
ssortingng houseName = "house"; // value to be tested ssortingng s; switch (houseName) { case var name when name.Equals("Bungalow", SsortingngComparison.InvariantCultureIgnoreCase): s = "Single glazed"; break; case var name when name.Equals("Church", SsortingngComparison.InvariantCultureIgnoreCase); s = "Stained glass"; break; ... default: s = "No windows (cold or dark)" break; }
Le magazine de studio visuel a un bel article sur les blocs de cas assortis de modèle qui pourraient mériter un coup d’oeil.
J’espère que cela aidera à convertir la chaîne entière en cas particulier soit en minuscule ou en majuscule et utiliser la chaîne en minuscules pour la comparaison:
public ssortingng ConvertMeasurements(ssortingng unitType, ssortingng value) { switch (unitType.ToLower()) { case "mmol/l": return (Double.Parse(value) * 0.0555).ToSsortingng(); case "mg/dl": return (double.Parse(value) * 18.0182).ToSsortingng(); } }
Voici une solution qui intègre la solution de @Magnus dans une classe:
public class SwitchCaseIndependent : IEnumerable> { private readonly Dictionary _cases = new Dictionary(SsortingngComparer.OrdinalIgnoreCase); public void Add(ssortingng theCase, Action theResult) { _cases.Add(theCase, theResult); } public Action this[ssortingng whichCase] { get { if (!_cases.ContainsKey(whichCase)) { throw new ArgumentException($"Error in SwitchCaseIndependent, \"{whichCase}\" is not a valid option"); } //otherwise return _cases[whichCase]; } } public IEnumerator> GetEnumerator() { return _cases.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _cases.GetEnumerator(); } }
Voici un exemple d’utilisation dans une application Windows Form simple:
var mySwitch = new SwitchCaseIndependent { {"hello", () => MessageBox.Show("hello")}, {"Goodbye", () => MessageBox.Show("Goodbye")}, {"SoLong", () => MessageBox.Show("SoLong")}, }; mySwitch["HELLO"]();
Si vous utilisez lambdas (comme dans l’exemple), vous obtenez des fermetures qui captureront vos variables locales (ce qui est assez proche du sentiment obtenu avec une instruction switch).
Comme il utilise un dictionnaire sous les couvertures, il obtient un comportement O (1) et ne repose pas sur la lecture de la liste de chaînes. Bien sûr, vous devez construire ce dictionnaire, et cela coûte probablement plus cher.
Il serait probablement judicieux d’append une méthode bool ContainsCase(ssortingng aCase)
simple qui appelle simplement la méthode ContainsKey
du dictionnaire.