Question Différence C # entre == et Equals ()


J'ai une condition dans une application Silverlight qui compare 2 chaînes, pour une raison quelconque lorsque j'utilise == ça revient faux tandis que .Equals() résultats vrai.

Voici le code:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

Une raison quelconque pour expliquer pourquoi cela se produit?


430
2018-05-02 13:36


origine


Réponses:


Quand == est utilisé sur une expression de type object, ça va résoudre à System.Object.ReferenceEquals.

Equals est juste un virtual méthode et se comporte comme tel, de sorte que la version substituée sera utilisée (qui, pour string type compare le contenu).


354
2018-05-02 13:39



Lors de la comparaison d’une référence d’objet à une chaîne (même si la référence à l’objet fait référence à une chaîne), le comportement spécial de la == L'opérateur spécifique à la classe de chaînes est ignoré.

Normalement (quand il ne s'agit pas de chaînes, c'est) Equals compare valeurs, tandis que == compare références d'objet. Si deux objets que vous comparez font référence à la même instance exacte d'un objet, les deux retourneront vrai, mais si le même contenu provient d'une source différente (une instance distincte avec les mêmes données), seul Equals retourner vrai. Cependant, comme indiqué dans les commentaires, string est un cas particulier car il remplace le == l'opérateur de sorte que lorsqu'il traite uniquement des références de chaîne (et non des références d'objet), seules les valeurs sont comparées même s'il s'agit d'instances distinctes. Le code suivant illustre les différences subtiles de comportements:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

La sortie est:

True True True
False True True
False False True

239
2018-05-02 13:40



== et .Equals dépendent tous les deux du comportement défini dans le type réel et du type réel sur le site d'appel. Les deux sont juste des méthodes / opérateurs qui peuvent être écrasés sur n'importe quel type et donné n'importe quel comportement que l'auteur désire. Dans mon expérience, je trouve qu'il est courant que les gens mettent en œuvre .Equals sur un objet, mais négligent de mettre en œuvre l'opérateur ==. Cela signifie que .Equals va effectivement mesurer l'égalité des valeurs tout en == va mesurer si oui ou non ils sont la même référence.

Lorsque je travaille avec un nouveau type dont la définition est en flux ou l’écriture d’algorithmes génériques, je trouve que la meilleure pratique est la suivante

  • Si je veux comparer des références en C #, j'utilise Object.ReferenceEquals directement (pas nécessaire dans le cas générique)
  • Si je veux comparer les valeurs que j'utilise EqualityComparer<T>.Default

Dans certains cas, lorsque je ressens l'usage de == est ambigu, je vais utiliser explicitement Object.Reference est égal au code pour supprimer l'ambiguïté.

Eric Lippert a récemment publié un billet sur le sujet de la raison pour laquelle il existe deux méthodes d'égalité dans le CLR. Cela vaut la peine de le lire


41
2018-05-02 13:47



Tout d'abord, il y a est une différence. Pour les nombres

> 2 == 2.0
True

> 2.Equals(2.0)
False

Et pour les cordes

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

Dans les deux cas, == se comporte plus utilement que .Equals


16
2017-08-15 11:15



J'ajouterais que si vous jetez votre objet sur une chaîne, cela fonctionnera correctement. C'est pourquoi le compilateur vous donnera un avertissement disant:

Comparaison de référence non intentionnelle possible; pour obtenir une comparaison de valeur,   lancer le côté gauche pour taper 'string'


12
2017-08-11 03:35



== Opérateur 1. Si les opérandes sont Types de valeur et leurs valeurs sont égales, il retourne true sinon false. 2. Si les opérandes sont Types de référence à l'exception de la chaîne et les deux font référence au même objet, elle renvoie true sinon false. 3. Si les opérandes sont de type chaîne et que leurs valeurs sont égales, elle renvoie true sinon false.

.Équivaut à 1. Si les opérandes sont des types de référence, il effectue Égalité de référence c'est-à-dire que si les deux se réfèrent au même objet, il renvoie vrai sinon faux. 2. Si les Opérandes sont des Types de Valeur alors contrairement à l'opérateur ==, il vérifie d'abord leur type et si leurs types sont identiques, il exécute == operator else il renvoie false.


8
2017-10-11 07:54



Autant que je comprends, la réponse est simple:

  1. == compare les références d'objets.
  2. .Equals compare le contenu de l'objet.
  3. Les types de données String agissent toujours comme la comparaison de contenu.

J'espère avoir raison et qu'il a répondu à votre question.


8
2017-11-27 09:56



Je suis un peu confus ici. Si le type d'exécution de Content est de type string, les deux == et Equals doivent retourner true. Cependant, comme cela ne semble pas être le cas, alors le type d'exécution de Content n'est pas une chaîne et l'appel de Equals à ce niveau effectue une égalité référentielle, ce qui explique l'échec d'Egals ("Energy Attack"). Cependant, dans le second cas, la décision concernant l'opérateur == statique surchargé à appeler est prise au moment de la compilation et cette décision semble être == (chaîne, chaîne). Cela me suggère que Content fournit une conversion implicite en string.


2
2018-05-02 16:02



Il y a une autre dimension à une réponse antérieure de @BlueMonkMN. La dimension supplémentaire est que la réponse à la question du titre de @ Drahcir telle qu’elle est énoncée dépend également de Comment nous sommes arrivés à string valeur. Pour illustrer:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));

Console.WriteLine("\n  Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

La sortie est:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True

2
2018-01-26 09:12