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?
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.
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
object
et string
afin d'effectuer un contrôle d'égalité de référenceobject
et string
afin d'effectuer un contrôle d'égalité de référenceobject
et string
afin d'effectuer un contrôle d'égalité de référencestring
et string
pour effectuer une vérification de valeur de chaînestring
et string
pour effectuer une vérification de valeur de chaînestring
et string
pour effectuer une vérification de valeur de chaîneobject
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 fauxIl 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));
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.
Les deux méthodes font la même chose fonctionnellement - elles comparent les valeurs .
Comme il est écrit sur MSDN:
String.Equals
method - Détermine si cette instance et un autre objet String spécifié ont la même valeur. ( http://msdn.Microsoft.com/en-us/library/858x0yyx.aspx )==
- Bien que chaîne soit un type de référence, les opérateurs d'égalité (==
et !=
) sont définis pour comparer les valeurs d'objets chaîne, et non de références. Cela rend le test d'égalité des chaînes plus intuitif. ( http://msdn.Microsoft.com/en-en/library/362314fe.aspx )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");
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".
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.
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