quelle devrait être la valeur de retour de StringComparison.OrdinalIgnoreCase?

Aug 24 2020

Quand j'exécute la ligne ci-dessous

returnVal=string.Compare("stringOne","stringTwo",StringComparison.OrdinalIgnoreCase);

J'obtiens le returnVal comme -5. Quelqu'un peut-il m'expliquer pourquoi c'est comme ça? Et aussi avec d'autres valeurs de chaîne, j'obtiens une valeur de retour comme 13,15 etc. Elle devrait généralement être -1,0,1. Si je ne me trompe pas.

Réponses

1 RufusL Aug 24 2020 at 21:38

"Il devrait généralement être -1,0,1. Si je ne me trompe pas"

Vous avez raison de dire que ce sont généralement les valeurs de retour de la Compareméthode et la pratique recommandée, même dans la documentation pour IComparer.Compare:

https://docs.microsoft.com/en-us/troubleshoot/dotnet/csharp/use-icomparable-icomparer

« Le IComparer.Compareprocédé nécessite une comparaison tertiaire. 1, 0Ou -1est renvoyée en fonction de si une valeur est supérieure, égale ou inférieure à l'autre. L'ordre de tri (croissant ou décroissant) peut être changé en commutant les opérateurs logiques dans ce procédé . "

Cependant, cela n'est appliqué nulle part.

De plus, la Stringclasse n'implémente pas IComparer<string>et cette surcharge de la Comparesignature n'est de toute façon pas définie dans cette interface.

Si nous regardons le code source de la Compareméthode ici , nous voyons que pour OrdinalIgnoreCase, il appelle la CompareOrdinalIgnoreCaseHelperméthode, qui renvoie la différence de valeur ascii entre la première paire de caractères non correspondants (après les avoir mis en majuscules) . Si les chaînes sont de longueurs différentes mais que les premiers caractères de la plus longue correspondent tous à ceux de la plus courte, la différence de longueur est renvoyée.

private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
{
    Contract.Requires(strA != null);
    Contract.Requires(strB != null);
    Contract.EndContractBlock();
    int length = Math.Min(strA.Length, strB.Length);

    fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
    {
        char* a = ap;
        char* b = bp;

        while (length != 0) 
        {
            int charA = *a;
            int charB = *b;

            Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");

            // uppercase both chars - notice that we need just one compare per char
            if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
            if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;

            //Return the (case-insensitive) difference between them.
            if (charA != charB)
                return charA - charB;

            // Next char
            a++; b++;
            length--;
        }

        return strA.Length - strB.Length;
    }
}

Par conséquent, nous devons toujours comparer le résultat d'une Compareméthode à 0et non -1ou 1.