web-dev-qa-db-fra.com

Pourquoi voudriez-vous utiliser String.Equals sur ==?

J'ai récemment découvert une grande base de code et j'ai remarqué que toutes les comparaisons de chaînes sont effectuées avec String.Equals() au lieu de ==

Quelle est la raison de cela, pensez-vous?

298
JamesBrownIsDead

Il est fort probable qu'une grande partie de la base de développeurs vienne d'un contexte Java où utiliser == pour comparer des chaînes est incorrect et ne fonctionne pas.

En C #, il n'y a pas de différence (pratique) (pour les chaînes) tant qu'elles sont saisies en tant que chaîne.

Si elles sont saisies sous la forme object ou T, alors voyez les autres réponses ici qui parlent de méthodes génériques ou de surcharge d'opérateurs, car vous souhaitez absolument utiliser la méthode Equals.

306
Matthew Scharley

Il existe une différence pratique entre string.Equals et ==

bool result = false;

object obj = "String";    
string str2 = "String";
string str3 = typeof(string).Name;
string str4 = "String";
object obj2 = str3;

// Comparision between object obj and string str2 -- Com 1
result = string.Equals(obj, str2);// true
result = String.ReferenceEquals(obj, str2); // true
result = (obj == str2);// true

// Comparision between object obj and string str3 -- Com 2
result = string.Equals(obj, str3);// true
result = String.ReferenceEquals(obj, str3); // false
result = (obj == str3);// false

// Comparision between object obj and string str4 -- Com 3
result = string.Equals(obj, str4);// true
result = String.ReferenceEquals(obj, str4); // true
result = (obj == str4);// true

// Comparision between string str2 and string str3 -- Com 4
result = string.Equals(str2, str3);// true
result = String.ReferenceEquals(str2, str3); // false
result = (str2 == str3);// true

// Comparision between string str2 and string str4 -- Com 5
result = string.Equals(str2, str4);// true
result = String.ReferenceEquals(str2, str4); // true
result = (str2 == str4);// true

// Comparision between string str3 and string str4 -- Com 6
result = string.Equals(str3, str4);// true
result = String.ReferenceEquals(str3, str4); // false
result = (str3 == str4);// true

// Comparision between object obj and object obj2 -- Com 7
result = String.Equals(obj, obj2);// true
result = String.ReferenceEquals(obj, obj2); // false
result = (obj == obj2);// false

Ajout de Watch

obj     "String" {1#}   object {string}
str2    "String" {1#}   string
str3    "String" {5#}   string
str4    "String" {1#}   string
obj2    "String" {5#}   object {string}

Maintenant, regardez {1#} et {5#}

Les références obj, str2, str4 et obj2 sont identiques.

obj et obj2 sont object type et les autres sont string type

Conclusion:

  1. com1 : résultat = (obj == str2); // vrai
    • compare object et string afin d'effectuer un contrôle d'égalité de référence
    • obj et str2 pointent vers la même référence, donc le résultat est vrai
  2. com2 : résultat = (obj == str3); // faux
    • compare object et string afin d'effectuer un contrôle d'égalité de référence
    • obj et str3 pointent vers les différentes références de sorte que le résultat est faux
  3. com3 : résultat = (obj == str4); // vrai
    • compare object et string afin d'effectuer un contrôle d'égalité de référence
    • obj et str4 pointent vers la même référence, donc le résultat est vrai
  4. com4 : résultat = (str2 == str3); // vrai
    • compare string et string pour effectuer une vérification de valeur de chaîne
    • str2 et str3 sont tous deux "String", donc le résultat est vrai
  5. com5 : résultat = (str2 == str4); // vrai
    • compare string et string pour effectuer une vérification de valeur de chaîne
    • str2 et str4 sont tous deux "String", donc le résultat est vrai
  6. com6 : résultat = (str3 == str4); // vrai
    • compare string et string pour effectuer une vérification de valeur de chaîne
    • str3 et str4 sont tous deux "String", donc le résultat est vrai
  7. com7 : resultat = (obj == obj2); // false - compare object et object de manière à obtenir une égalité de référence check - obj et obj2 pointent vers les différentes références, donc le résultat est faux
92
vikas

Il y a une différence subtile mais très importante entre == et les méthodes String.Equals:

class Program
{
    static void Main(string[] args)
    {
        CheckEquality("a", "a");
        Console.WriteLine("----------");
        CheckEquality("a", "ba".Substring(1));
    }

    static void CheckEquality<T>(T value1, T value2) where T : class
    {
        Console.WriteLine("value1: {0}", value1);
        Console.WriteLine("value2: {0}", value2);

        Console.WriteLine("value1 == value2:      {0}", value1 == value2);
        Console.WriteLine("value1.Equals(value2): {0}", value1.Equals(value2));

        if (typeof(T).IsEquivalentTo(typeof(string)))
        {
            string string1 = (string)(object)value1;
            string string2 = (string)(object)value2;
            Console.WriteLine("string1 == string2:    {0}", string1 == string2);
        }
    }
}

Produit cette sortie:

value1: a
value2: a
value1 == value2:      True
value1.Equals(value2): True
string1 == string2:    True
----------
value1: a
value2: a
value1 == value2:      False
value1.Equals(value2): True
string1 == string2:    True

Vous pouvez voir que l'opérateur == renvoie false en deux chaînes évidemment égales. Pourquoi? Parce que l'opérateur == utilisé dans la méthode générique est résolu pour être la méthode op_equal définie par System.Object (la seule garantie de T de la méthode au moment de la compilation), ce qui signifie qu'il s'agit d'une égalité de référence plutôt que d'une égalité de valeur.

Lorsque vous avez explicitement typé deux valeurs comme System.String, alors == a une sémantique d'égalité de valeurs car le compilateur résout le == en System.String.op_equal au lieu de System.Object.op_equal.

Donc, pour être prudent, j’utilise presque toujours String.Equals, à la place, j’obtiens toujours la sémantique d’égalité des valeurs que je veux.

Et pour éviter NullReferenceExceptions si l’une des valeurs est nulle, j’utilise toujours la méthode static String.Equals:

bool true = String.Equals("a", "ba".Substring(1));
65
Andrew Arnott

String.Equals propose des surcharges pour gérer les boîtiers et les comparaisons tenant compte de la culture. Si votre code ne les utilise pas, les développeurs peuvent uniquement être utilisés en Java, où (comme le dit Matthew), vous devez utiliser la méthode .Equals pour effectuer des comparaisons de contenu.

37
Michael Petrotta

Les deux méthodes font la même chose fonctionnellement - elles comparent les valeurs .
Comme il est écrit sur MSDN:

Mais si l'une de vos instances de chaîne est null, ces méthodes fonctionnent différemment:

string x = null;
string y = "qq";
if (x == y) // returns false
    MessageBox.Show("true");
else
    MessageBox.Show("false");

if (x.Equals(y)) // returns System.NullReferenceException: Object reference not set to an instance of an object. - because x is null !!!
    MessageBox.Show("true");
else
    MessageBox.Show("false");
20
thezar

Il y a un article sur cet article qui pourrait vous intéresser, avec quelques citations de Jon Skeet. Il semble que l'utilisation est à peu près la même chose.

Jon Skeet déclare que les performances de l'instance Equals sont "légèrement meilleures lorsque les chaînes sont courtes. À mesure que la longueur des chaînes augmente, cette différence devient complètement insignifiante".

16

Je veux ajouter qu'il y a une autre différence. C'est lié à ce qu'Andrew publie.

Il est également lié à un très ennuyeux de trouver un bogue dans notre logiciel. Voir l'exemple simplifié suivant (j'ai également omis la vérification nulle).

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return numberTextBoxTextValue.Equals(SPECIAL_NUMBER)
}

Ceci compilera et retournera toujours false. Alors que ce qui suit donnera une erreur de compilation:

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return (numberTextBoxTextValue == SPECIAL_NUMBER);
}

Nous avons dû résoudre un problème similaire dans lequel quelqu'un comparait des énumérations de types différents en utilisant Equals. Vous allez lire BEAUCOUP de fois avant de réaliser que c'est la cause du bogue. Surtout si la définition de SPECIAL_NUMBER ne se trouve pas à proximité de la zone à problèmes.

C'est pourquoi je suis vraiment contre l'utilisation d'Equal sur des situations où cela n'est pas nécessaire. Vous perdez un peu de la sécurité de type.

5
Matthijs Wessels

Je viens de me cogner la tête contre un mur pour essayer de résoudre un bug car j'ai lu cette page et conclu qu'il n'y avait aucune différence significative dans la pratique. Je posterai donc ce lien ici au cas où quelqu'un trouverait des résultats différents. sur == et égal.

Object == l'égalité échoue, mais .Equals réussit. Cela a-t-il un sens?

string a = "x";
string b = new String(new []{'x'});

Console.WriteLine("x == x " + (a == b));//True
Console.WriteLine("object x == x " + ((object)a == (object)b));//False
Console.WriteLine("x equals x " + (a.Equals(b)));//True
Console.WriteLine("object x equals x " + (((object)a).Equals((object)b)));//True
4
Andrew