Question

Comparer une chaîne en C# est assez simple.En fait, il existe plusieurs façons de procéder.J'en ai répertorié quelques-uns dans le bloc ci-dessous.Ce qui m'intéresse, ce sont les différences entre eux et quand l'un doit-il être utilisé par rapport aux autres ?Faut-il l’éviter à tout prix ?Y a-t-il d'autres que je n'ai pas répertoriés ?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(Note:Je recherche l'égalité dans cet exemple, ni inférieure ni supérieure à, mais n'hésitez pas à commenter cela également)

Était-ce utile?

La solution

Voici les règles de fonctionnement de ces fonctions :

stringValue.CompareTo(otherStringValue)

  1. null vient avant une chaîne
  2. il utilise CultureInfo.CurrentCulture.CompareInfo.Compare, ce qui signifie qu'il utilisera une comparaison dépendante de la culture.Cela pourrait signifier que ß comparera égal à SS en Allemagne, ou similaire

stringValue.Equals(otherStringValue)

  1. null n'est pas considéré comme égal à quoi que ce soit
  2. sauf si vous spécifiez un StringComparison option, il utilisera ce qui ressemble à une vérification directe de l’égalité ordinale, c’est-à-dire ß n'est pas la même chose que SS, dans n'importe quelle langue ou culture

stringValue == otherStringValue

  1. Ce n'est pas la même chose que stringValue.Equals().
  2. Le == l'opérateur appelle le statique Equals(string a, string b) méthode (qui à son tour va à un interne EqualsHelper pour faire la comparaison.
  3. Appel .Equals() sur un null la chaîne obtient null exception de référence, alors que == ne fait pas.

Object.ReferenceEquals(stringValue, otherStringValue)

Vérifie simplement que les références sont les mêmes, c'est-à-direil ne s'agit pas seulement de deux chaînes avec le même contenu, vous comparez un objet chaîne avec lui-même.


Notez qu'avec les options ci-dessus qui utilisent des appels de méthode, il existe des surcharges avec plus d'options pour spécifier comment comparer.

Mon conseil si vous souhaitez simplement vérifier l'égalité est de décider si vous souhaitez ou non utiliser une comparaison dépendante de la culture, puis d'utiliser .CompareTo ou .Equals, selon le choix.

Autres conseils

Depuis MSDN :

"La méthode de comparaison a été conçue principalement pour une utilisation dans les opérations de tri ou d'alphabétisation.Il ne doit pas être utilisé lorsque l'objectif principal de l'appel de la méthode est de déterminer si deux chaînes sont équivalentes.Pour déterminer si deux chaînes sont équivalentes, appelez la méthode égale. "

Ils suggèrent d'utiliser .Equals au lieu de .CompareTo en recherchant uniquement l’égalité.Je ne sais pas s'il y a une différence entre .Equals et == pour le string classe.J'utiliserai parfois .Equals ou Object.ReferenceEquals au lieu de == pour mes propres cours au cas où quelqu'un viendrait plus tard et redéfinirait le == opérateur pour cette classe.

Si jamais vous êtes curieux de connaître les différences entre les méthodes BCL, Réflecteur est votre ami :-)

Je suis ces directives :

Correspondance exacte: MODIFIER:Auparavant, j'utilisais toujours l'opérateur == sur le principe qu'à l'intérieur de Equals(string, string), l'opérateur object == est utilisé pour comparer les références d'objet, mais il semble que strA.Equals(strB) soit toujours 1 à 11 % plus rapide que la chaîne. Equals(strA, strB), strA == strB et string.CompareOrdinal(strA, strB).J'ai testé en boucle avec un StopWatch sur les valeurs de chaîne internes/non internes, avec des longueurs de chaîne identiques/différentes et des tailles variables (1B à 5 Mo).

strA.Equals(strB)

Correspondance lisible par l'homme (cultures occidentales, insensible à la casse) :

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Correspondance lisible par l'homme (toutes les autres cultures, casse/accent/kana/etc insensibles définis par CultureInfo) :

string.Compare(strA, strB, myCultureInfo) == 0

Correspondance lisible par l'homme avec des règles personnalisées (toutes les autres cultures) :

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0

Comme Éd a dit, CompareTo est utilisé pour le tri.

Il existe cependant une différence entre .Equals et ==.

== se résout en essentiellement le code suivant :

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

La raison simple est que la suivante lèvera une exception :

string a = null;
string b = "foo";

bool equal = a.Equals(b);

Et ce qui suit ne le sera pas :

string a = null;
string b = "foo";

bool equal = a == b;

De bonnes explications et pratiques sur les problèmes de comparaison de chaînes peuvent être trouvées dans l'article Nouvelles recommandations pour l'utilisation de chaînes dans Microsoft .NET 2.0 et aussi dans Meilleures pratiques d'utilisation des chaînes dans le .NET Framework.


Chacune des méthodes mentionnées (et autres) a un objectif particulier.La principale différence entre eux réside dans le type de Énumération StringComparison ils utilisent par défaut.Il existe plusieurs options :

  • CultureActuelle
  • CurrentCultureIgnoreCase
  • Culture Invariante
  • InvariantCultureIgnoreCase
  • Ordinal
  • OrdinalIgnoreCase

Chacun des types de comparaison ci-dessus cible différents cas d'utilisation :

  • Ordinal
    • Identifiants internes sensibles à la casse
    • Identifiants sensibles à la casse dans des normes telles que XML et HTTP
    • Paramètres liés à la sécurité sensibles à la casse
  • OrdinalIgnoreCase
    • Identifiants internes insensibles à la casse
    • Identifiants insensibles à la casse dans des normes telles que XML et HTTP
    • Chemins de fichiers (sous Microsoft Windows)
    • Clés/valeurs de registre
    • Variables d'environnement
    • Identifiants de ressources (noms de handle, par exemple)
    • Paramètres liés à la sécurité qui ne sont pas sensibles à la casse
  • InvariantCulture ou InvariantCultureIgnoreCase
    • Certaines données persistantes linguistiquement pertinentes
    • Affichage des données linguistiques nécessitant un ordre de tri fixe
  • CurrentCulture ou CurrentCultureIgnoreCase
    • Données affichées à l'utilisateur
    • La plupart des entrées des utilisateurs

Noter que Énumération StringComparison ainsi que les surcharges pour les méthodes de comparaison de chaînes, existent depuis .NET 2.0.


Méthode String.CompareTo (String)

Est-ce en fait une implémentation sûre de type Méthode IComparable.CompareTo.Interprétation par défaut :Culture actuelle.

Usage:

La méthode CompareTo a été conçue principalement pour être utilisée dans les opérations de tri ou d'alphabétisation.

Ainsi

L'implémentation de l'interface IComparable utilisera nécessairement cette méthode

Méthode String.Compare

Un membre statique de Classe de chaîne qui a de nombreuses surcharges.Interprétation par défaut :Culture actuelle.

Dans la mesure du possible, vous devez appeler une surcharge de la méthode Compare qui inclut un paramètre StringComparison.

Méthode String.Equals

Remplacé par la classe Object et surchargé pour la sécurité du type.Interprétation par défaut :Ordinal.Remarquerez que:

Les méthodes d'égalité de la classe String incluent statique est égal à, le opérateur statique ==, et le méthode d'instance Égal à.


Classe StringComparer

Il existe également une autre manière de gérer les comparaisons de chaînes, notamment pour le tri :

Vous pouvez utiliser le Classe StringComparer pour créer une comparaison spécifique à un type pour trier les éléments d'une collection générique.Les classes telles que Hashtable, Dictionary, SortedList et SortedList utilisent la classe StringComparer à des fins de tri.

Non pas que les performances soient généralement importantes dans 99 % des cas, mais si vous deviez le faire en boucle plusieurs millions de fois, je vous suggère fortement d'utiliser .Equals ou == car dès qu'il trouve un caractère cela ne correspond pas, le tout est considéré comme faux, mais si vous utilisez CompareTo, il devra déterminer quel caractère est inférieur à l'autre, ce qui entraînera un temps de performance légèrement inférieur.

Si votre application doit être exécutée dans différents pays, je vous recommande de jeter un œil aux implications de CultureInfo et éventuellement d'utiliser .Equals.Comme je n'écris que des applications pour les États-Unis (et que je m'en fiche si cela ne fonctionne pas correctement par quelqu'un), j'utilise toujours ==.

Dans les formulaires que vous avez répertoriés ici, il n'y a pas beaucoup de différence entre les deux. CompareTo finit par appeler un CompareInfo méthode qui fait une comparaison en utilisant la culture actuelle ; Equals est appelé par le == opérateur.

Si l’on considère les surcharges, les choses deviennent différentes. Compare et == ne peut utiliser la culture actuelle que pour comparer une chaîne. Equals et String.Compare peut prendre un StringComparison argument d'énumération qui vous permet de spécifier des comparaisons insensibles à la culture ou à la casse.Seulement String.Compare vous permet de spécifier un CultureInfo et effectuez des comparaisons en utilisant une culture autre que la culture par défaut.

En raison de sa polyvalence, je trouve que j'utilise String.Compare plus que toute autre méthode de comparaison ;cela me permet de préciser exactement ce que je veux.

Une GRANDE différence à noter est que .Equals() lèvera une exception si la première chaîne est nulle, alors que == ne le fera pas.

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");
  • s1.CompareTo(s2) : Ne PAS utiliser si l'objectif principal est de déterminer si deux chaînes sont équivalentes.
  • s1 == s2 : Impossible d'ignorer le cas
  • s1.Equals(s2, StringComparison) : Lève NullReferenceException si s1 est nul
  • String.Equals(s2, StringComparison) : Par processus d'élimination, cela statique la méthode est la GAGNANT (en supposant un cas d'utilisation typique pour déterminer si deux chaînes sont équivalentes) !

Utiliser .Equals est également beaucoup plus facile à lire.

avec .Equals, vous bénéficiez également des options StringComparison.très pratique pour ignorer la casse et d'autres choses.

au fait, cela sera évalué à faux

string a = "myString";
string b = "myString";

return a==b

Puisque == compare les valeurs de a et b (qui sont des pointeurs), cela ne sera évalué comme vrai que si les pointeurs pointent vers le même objet en mémoire..Equals déréférence les pointeurs et compare les valeurs stockées au niveau des pointeurs.a.Equals(b) serait vrai ici.

et si vous remplacez b par :

b = "MYSTRING";

alors a.Equals(b) est faux, mais

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

serait vrai

a.CompareTo(b) appelle la fonction CompareTo de la chaîne qui compare les valeurs aux pointeurs et renvoie <0 si la valeur stockée en a est inférieure à la valeur stockée en b, renvoie 0 si a.Equals(b) est vrai, et >0 sinon.Cependant, ceci est sensible à la casse, je pense qu'il existe éventuellement des options permettant à CompareTo d'ignorer la casse, etc., mais je n'ai pas le temps de regarder maintenant.Comme d'autres l'ont déjà dit, cela serait fait pour le tri.Comparer l'égalité de cette manière entraînerait une surcharge inutile.

Je suis sûr que je laisse des choses de côté, mais je pense que cela devrait suffire pour commencer à expérimenter si vous avez besoin de plus de détails.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top