web-dev-qa-db-fra.com

C # différence entre == et égal à ()

J'ai une condition dans une application silverlight qui compare 2 chaînes, pour une raison quelconque lorsque j'utilise ==, il retourne false tandis que .Equals() retourne true.

Voici le code:

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

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

Une raison pour laquelle cela se produit?

508
Drahcir

Lorsque _==_ est utilisé dans une expression de type object, la résolution est System.Object.ReferenceEquals .

Equals est simplement une méthode virtual et se comporte comme tel. La version remplacée est donc utilisée (ce qui, pour le type string, compare le contenu).

403
Mehrdad Afshari

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

Normalement (lorsqu'il ne s'agit pas de chaînes, c'est-à-dire), 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, ils retourneront tous les deux la valeur true, mais si l'un d'entre eux a le même contenu et provient d'une source différente (est une instance séparée avec les mêmes données), seul Equals retourne vrai. Toutefois, comme indiqué dans les commentaires, chaîne constitue un cas particulier car elle remplace l'opérateur == de sorte que, lorsqu'il s'agit uniquement de références de chaîne (et non de 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 dans les 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
287
BlueMonkMN

== et .Equals dépendent tous deux du comportement défini dans le type réel et du type réel sur le site d'appel. Les deux ne sont que des méthodes/opérateurs qui peuvent être remplacés par n'importe quel type et par tous les comportements souhaités par l'auteur. D'après mon expérience, il est courant que les gens implémentent .Equals sur un objet, mais négligent d'implémenter l'opérateur ==. Cela signifie que .Equals mesurera en réalité l’égalité des valeurs tandis que == mesurera si elles sont ou non la même référence.

Lorsque je travaille avec un nouveau type dont la définition est en train de changer ou que j'écris des 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 directement Object.ReferenceEquals (inutile dans le cas générique)
  • Si je veux comparer des valeurs, j'utilise EqualityComparer<T>.Default

Dans certains cas, lorsque j'estime que l'utilisation de == est ambiguë, j'utiliserai explicitement Object.Reference égale dans le code pour supprimer l'ambiguïté.

Eric Lippert a récemment publié un article sur son blog expliquant pourquoi il existe deux méthodes d'égalité dans le CLR. Ça vaut la lecture

45
JaredPar

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

> 2 == 2.0
True

> 2.Equals(2.0)
False

Et pour les ficelles

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

> x.Equals(null)
NullReferenceException

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

20
Colonel Panic

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

Comparaison de référence involontaire possible; pour obtenir une comparaison de valeur, transformez le côté gauche en "chaîne"

13
MikeKulls

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

  1. == compare les références d'objet.
  2. .Equals compare le contenu de l'objet.
  3. Les types de données de chaîne agissent toujours comme une comparaison de contenu.

J'espère avoir raison et que cela répond à votre question.

11
Liraz Shaka Amir

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

. Égal 1. Si les opérandes sont des types de référence, elle exécute égalité de référence si les deux font référence au même objet, elle renvoie vrai sinon faux. 2. Si les opérandes sont des types de valeur, contrairement à l'opérateur ==, il vérifie d'abord leur type et si leur type est identique, il exécute l'opérateur == sinon, il renvoie la valeur false.

9
kashif

Puisque la version statique de la méthode .Equal n'a pas été mentionnée jusqu'à présent, j'aimerais ajouter ceci ici pour résumer et comparer les 3 variations.

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

MyString est une variable qui provient d'un autre endroit du code.

Informations générales et à résumer:

Dans Java, l'utilisation de == pour comparer des chaînes ne doit pas être utilisée. Je le mentionne au cas où vous auriez besoin d’utiliser les deux langues et de vous informer que l’utilisation de == peut également être remplacée par quelque chose de meilleur en C #.

En C #, il n'y a pas de différence pratique pour comparer des chaînes à l'aide de la méthode 1 ou de la méthode 2 tant que les deux sont de type chaîne. Cependant, si l'une est nulle, si elle est d'un autre type (comme un entier) ou si elle représente un objet ayant une référence différente, alors, comme le montre la question initiale, vous pouvez vous rendre compte que la comparaison du contenu pour l'égalité ne renvoie pas ce que vous vous attendez.

Solution suggérée:

Parce que l'utilisation de == n'est pas exactement la même chose que d'utiliser .Equals lors de la comparaison, vous pouvez utiliser la méthode statique String.Equals au lieu. De cette façon, si les deux côtés ne sont pas du même type, vous comparerez quand même le contenu et si l'un est nul, vous éviterez l'exception.

   bool areEqual = String.Equals("Somestring", MyString);  

C'est un peu plus d'écrire, mais à mon avis, plus sûr à utiliser.

Voici quelques informations copiées à partir de Microsoft:

public static bool Equals (string a, string b);

Paramètres

a String

La première chaîne à comparer, ou null.

b String

La deuxième chaîne à comparer, ou null.

Renvoie Boolean

true si la valeur de a est identique à la valeur de b; sinon, false. Si a et b sont tous deux null, la méthode retourne true.

4
levteck

Juste comme un ajout aux réponses déjà bonnes: Ce comportement n'est PAS limité aux chaînes ou à la comparaison de différents types numériques. Même si les deux éléments sont de type objet du même type sous-jacent. "==" ne fonctionnera pas.

La capture d'écran suivante montre les résultats de la comparaison de deux objets {int} - valeurs

Example From VS2017

2
Ole Albers

@BlueMonkMN a une autre dimension. 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 à la valeur string. 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
Novichok

Ajouter un autre point à la réponse.

La méthode .EqualsTo() vous permet de comparer la culture et la sensibilité à la casse.

2
Bala

Je suis un peu confus ici. Si le type de contenu d'exécution est de type chaîne, alors == et Equals doivent renvoyer true. Toutefois, comme cela ne semble pas être le cas, le type de contenu d'exécution n'est pas une chaîne et l'appel d'Equal sur une égalité référentielle lui est appliqué, ce qui explique pourquoi Echals ("Energy Attack") échoue. Toutefois, dans le second cas, la décision relative à l'opérateur appelé == statique surchargé doit être appelée 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 chaîne.

2
Mehmet Aras

Le jeton == en C # est utilisé pour deux opérateurs de vérification d'égalité différents. Lorsque le compilateur rencontre ce jeton, il vérifie si l'un des types comparés a implémenté une surcharge d'opérateur d'égalité pour les types de combinaison spécifiques comparés (*) ou pour une combinaison de types vers laquelle les deux types peuvent être convertis. Si le compilateur découvre une telle surcharge, il l'utilisera. Sinon, si les deux types sont tous deux des types de référence et qu'ils ne sont pas des classes non apparentées (que ce soit une interface ou des classes apparentées), le compilateur considérera == comme un opérateur de comparaison de références. Si aucune des conditions ne s'applique, la compilation échouera.

Notez que d'autres langues utilisent des jetons distincts pour les deux opérateurs de contrôle d'égalité. Dans VB.NET, par exemple, le jeton = est utilisé dans les expressions uniquement pour l'opérateur de contrôle d'égalité surchargeable, et Is est utilisé en tant qu'opérateur de test de référence ou de test null. L'utilisation de = sur un type qui ne remplace pas l'opérateur de vérification d'égalité échouera, de même que toute tentative d'utilisation de Is à des fins autres que le test d'égalité ou de nullité de référence.

(*) Les types ne surchargent généralement que l'égalité pour la comparaison avec eux-mêmes, mais il peut être utile que les types surchargent l'opérateur d'égalité pour la comparaison avec d'autres types particuliers; par exemple, int aurait pu (et IMHO aurait dû mais ne l'a pas fait) défini des opérateurs d'égalité pour la comparaison avec float, de sorte que 16777217 ne se signale pas comme étant égal à 16777216f. En l'état, vu qu'aucun opérateur de ce type n'est défini, C # va promouvoir le int en float, en l'arrondissant à 16777216f avant que l'opérateur de contrôle d'égalité ne le voie; cet opérateur voit alors deux nombres égaux en virgule flottante et les signale égaux, ignorant l'arrondi.

0
supercat

Vraiment d'excellentes réponses et exemples!

Je voudrais juste ajouter la différence fondamentale entre les deux,

Les opérateurs tels que == ne sont pas polymorphes, alors que Equals est

Avec ce concept en tête, si vous travaillez sur un exemple (en regardant le type de référence gauche et droit, et en vérifiant si le type est réellement = = surchargé et égal à surchargé), vous êtes certain d'obtenir la bonne réponse. .

0
Manish Basantani