113 votes

Comment faire pour que l'instruction C # Switch utilise IgnoreCase

Si j'ai une instruction switch-case où l'objet dans le commutateur est une chaîne, est-il possible de faire de toute façon ignorer la comparaison de cas?

J'ai par exemple:

 string s = "house";
switch (s)
{
  case "houSe": s = "window";
}
 

Obtiendra la valeur "fenêtre". Comment remplacer l'instruction switch-case pour qu'elle compare les chaînes en utilisant ignoreCase?

97voto

Nick Craver Points 313913

Une approche plus simple consiste simplement à mettre en minuscule votre chaîne avant qu'elle ne pénètre dans l'instruction switch et à réduire la casse.

En fait, la tige est un peu meilleure du point de vue de la performance en nanosecondes extrêmes, mais moins naturelle à regarder.

Par exemple:

 string s = "house"; 
switch (s.ToLower()) { 
  case "house": 
    s = "window"; 
    break;
}
 

72voto

Jeffrey L Whitledge Points 27574

Comme vous semblez être au courant, la mise en minuscules deux chaînes et de les comparer n'est pas le même que le fait de faire un ignorer les cas de comparaison. Il y a beaucoup de raisons à cela. Par exemple, la norme Unicode permet de texte avec des signes diacritiques pour être codées de multiples façons. Certains caractères comprend à la fois la base et le caractère diacritique dans un seul point de code. Ces caractères peuvent également être représentés par le caractère de base suivie par une combinaison de caractère diacritique. Ces deux représentations sont égaux pour tous les usages, et de la culture-connaissance des comparaisons de chaînes dans le .NET Framework correctement les identifier comme des égaux, avec le CurrentCulture ou InvariantCulture (avec ou sans IgnoreCase). Une comparaison ordinale, d'autre part, à tort considérer comme inégal.

Malheureusement, switch ne rien faire mais d'une comparaison ordinale. Une comparaison ordinale est très bien pour certains types d'applications, comme l'analyse d'un fichier ASCII avec rigidement définis codes, mais ordinale de comparaison de chaîne est mauvais pour la plupart des autres utilisations.

Ce que j'ai fait dans le passé pour obtenir le comportement correct est juste se moquer de ma propre instruction switch. Il y a beaucoup de façons de le faire. Un autre moyen serait de créer un List<T> de paires de cas des chaînes et des délégués. La liste peut être recherché à l'aide de la bonne comparaison de chaînes de caractères. Lorsque la correspondance est trouvée, alors l'associé délégué ne peut être invoquée.

Une autre option est de le faire à l'évidence de la chaîne d' if des déclarations. Cela s'avère généralement être pas aussi mauvais que cela puisse paraître, puisque la structure est très régulier.

La grande chose à ce sujet est qu'il n'y a pas vraiment de performances en se moquant de votre propre fonctionnalité de commutateur lorsque l'on compare contre les cordes. Le système ne va pas faire un O(1) sauter de la table de la façon dont il peut avec des entiers, donc ça va être une comparaison de chaque chaîne de caractères un à un moment de toute façon.

Si il y a de nombreux cas être comparé, et la performance est un problème, alors la List<T> option décrite ci-dessus pourrait être remplacé par un triées dictionnaire ou une table de hachage. Alors, les performances peuvent potentiellement atteindre ou de dépasser l'instruction switch option.

Voici un exemple de la liste des délégués:

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();
}

Bien sûr, vous voulez probablement ajouter quelques paramètres standard et, éventuellement, d'un type de retour de la CustomSwitchDestination délégué. Et vous aurez envie de prendre de meilleures les noms!

Si le comportement de chacun de vos cas n'est pas prête à déléguer l'invocation de cette manière, comme si divers paramètres sont nécessaires, puis vous êtes coincé avec enchaîné if relevés. J'ai aussi fait quelques fois.

    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";
    }

37voto

uli78 Points 410

Dans certains cas, il peut être judicieux d'utiliser une énumération. Donc, commencez par analyser l'énumération (avec le drapeau ignoreCase true) et ensuite avoir un commutateur sur l'énumération.

 SampleEnum Result;
bool Success = SampleEnum.TryParse(inputText, true, out Result);
switch (Result) {...}
 

24voto

Magnus Points 20478

Une façon possible serait d'utiliser un dictionnaire de cas ignoré avec un délégué d'action.

 string s = null;
var dic = new Dictionary<string, Action>(StringComparer.CurrentCultureIgnoreCase)
{
    {"house",  () => s = "window"},
    {"house2", () => s = "window2"}
};

dic["HouSe"]();
 

0voto

Jesse MacNett Points 19

(AVERTISSEMENT: c'est plus un exercice de réflexion qu'autre chose)

Je dois y penser, et il y a une façon de le faire nativement ... en quelque sorte. Cela demanderait beaucoup d'efforts manuels de votre part, mais vous pourriez le faire, étant donné que vous vouliez prendre le temps de déterminer vos valeurs de `` cas '' à l'avance, comme indiqué ci-dessous.

Je ne dis pas que c'est pratique , mais hein ... vous pouvez le faire :)

     private const int CASE_1_HASH = 1824343508;
    private const int CASE_2_HASH = -2010407750;
    private const int CASE_3_HASH = -1043111430;

    private void btnSwitchHashTest_Click(object sender, EventArgs e)
    {
        string test1 = "mytestvalue";
        string test2 = "myTestValue";

        int t1hash = test1.GetHashCode();
        int t2hash = test2.GetHashCode();

        t1hash = StringComparer.CurrentCultureIgnoreCase.GetHashCode(test1);
        t2hash = StringComparer.CurrentCultureIgnoreCase.GetHashCode(test2);

        switch ( t1hash )
        {
            case CASE_1_HASH:
                // do something
                break;
            case CASE_2_HASH:
                // do something else
                break;
            case CASE_3_HASH:
                // do something else alternatively
                break;
            // ... etc
        }
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X