J'ai une condition dans une application Silverlight qui compare 2 chaînes, pour une raison quelconque, lorsque je l'utilise, ==
elle renvoie false tandis que .Equals()
renvoie 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?
==
, mais les opérateurs ne sont pas polymorphes. Dans ce code, l'==
opérateur est appelé sur typeobject
, qui effectue une comparaison d'identité au lieu d'une valeur.==
surcharge en fonction du type de compilation des opérandes. LaContent
propriété estobject
. Les opérateurs ne sont pas virtuels, donc l'implémentation par défaut de==
est appelée, donnant une comparaison d'égalité de référence. Avec Equals, l'appel passe à la méthode virtuelleobject.Equals(object)
;string
remplace cette méthode et effectue une comparaison ordinale du contenu de la chaîne. Voir msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx et referencesource.microsoft.com/#mscorlib/system/string.cs,507 .==
a le type au moment de la compilationobject
et le côté droit a le type austring
moment de la compilation, alors le compilateur C # doit choisir la surcharge (problématique, dans ce cas)operator ==(object, object)
; mais il sera un avertissement à la compilation qu'il pourrait être involontaire. Lisez donc les avertissements à la compilation! Pour résoudre le problème et continuer à l'utiliser==
, placez le côté gauche surstring
. Si je me souviens bien, le texte d'avertissement le suggère.Réponses:
Lorsque
==
est utilisé sur une expression de typeobject
, il sera résolu enSystem.Object.ReferenceEquals
.Equals
est juste unevirtual
méthode et se comporte comme telle, donc la version surchargée sera utilisée (qui, pour lestring
type, compare le contenu).la source
object
type (notez la police monospace) est techniquement censé être "une expression de typeSystem.Object
". Cela n'a rien à voir avec le type d'exécution de l'instance à laquelle fait référence l'expression. Je pense que la déclaration «les opérateurs définis par l'utilisateur sont traités comme desvirtual
méthodes» est extrêmement trompeuse. Ils sont traités comme des méthodes surchargées et ne dépendent que du type de compilation des opérandes. En fait, une fois l'ensemble des opérateurs définis par l'utilisateur candidats calculés, le reste de la procédure de liaison sera exactement l'algorithme de résolution de surcharge de méthodevirtual
résolution de la méthode dépend du type d'exécution réel d'une instance, alors que cela est complètement ignoré dans la résolution de surcharge de l'opérateur, et c'est en effet tout le point de ma réponse.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 les valeurs , tout en==
comparant les références d'objet . Si deux objets que vous comparez se réfèrent à la même instance exacte d'un objet, alors les deux renverront true, mais si l'un a le même contenu et provient d'une source différente (est une instance distincte avec les mêmes données), seul Equals sera retourner vrai. Cependant, comme indiqué dans les commentaires, la chaîne est 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 de comportements:La sortie est:
la source
==
et.Equals
dépendent tous deux du comportement défini dans le type réel et le type réel sur le site d'appel. Les deux ne sont que des méthodes / opérateurs qui peuvent être remplacés sur n'importe quel type et compte tenu du comportement souhaité par l'auteur. D'après mon expérience, je trouve qu'il est courant pour les gens d'implémenter.Equals
sur un objet mais néglige d'implémenter l'opérateur==
. Cela signifie que.Equals
va réellement mesurer l'égalité des valeurs tout==
en mesurant si elles sont ou non la même référence.Lorsque je travaille avec un nouveau type dont la définition est en flux ou que j'écris des algorithmes génériques, je trouve que la meilleure pratique est la suivante
Object.ReferenceEquals
directement (pas nécessaire dans le cas générique)EqualityComparer<T>.Default
Dans certains cas, lorsque je pense que l'utilisation de
==
est ambigu, j'utiliserai explicitementObject.Reference
égal dans le code pour supprimer l'ambiguïté.Eric Lippert a récemment publié un article sur le blog expliquant pourquoi il existe 2 méthodes d'égalité dans le CLR. Ça vaut le coup d'être lu
la source
== Opérateur
.Équivaut à
la source
==
opérateur peut être surchargé pour tout type, pas seulement pour la chaîne. La description d'une exception de cas spécial uniquement pour la chaîne représente de manière erronée la sémantique de l'opérateur. Il serait plus précis, mais peut-être pas terriblement utile, de dire "si les opérandes sont des types de référence, il renvoie vrai si les opérandes se réfèrent au même objet, sauf en cas de surcharge applicable, auquel cas l'implémentation de cette surcharge détermine le résultat ". Il en va de même pourEquals
la complication supplémentaire qu'il s'agit d'une méthode virtuelle, de sorte que son comportement peut être outrepassé et surchargé.Premièrement, il y a une différence. Pour les chiffres
Et pour les cordes
Dans les deux cas,
==
se comporte plus utilement que.Equals
la source
==
opérateur comme une bonne chose. Par exemple, 16777216.0f doit-il être égal à (int) 16777217, (double) 16777217.0, les deux ou ni l'un ni l'autre? Les comparaisons entre les types intégraux sont bonnes, mais les comparaisons à virgule flottante ne doivent être effectuées qu'à mon humble avis avec des valeurs explicitement converties en types correspondants. La comparaison de afloat
à quelque chose d'autre que afloat
, ou dedouble
à quelque chose d'autre que adouble
, me semble être une odeur de code majeure qui ne devrait pas être compilée sans diagnostic.x == y
n'implique pasx/3 == y/3
(essayezx = 5
ety = 5.0
)./
division entière est un défaut dans la conception de C # et Java.div
Les` are much better. The problems with
== `de Pascal et même de VB.NET sont pires, cependant:x==y
ety==z
cela n'implique pas celax==z
(considérez les trois nombres dans mon commentaire précédent). Quant à la relation que vous suggérez, même six
ety
sont les deuxfloat
ou les deuxdouble
,x.equals((Object)y)
n'implique pas que1.0f/x ==
1.0f / y` (si j'avais mes druthers, cela garantirait cela; même si==
ne fait pas de distinction entre le positif et le zéro,Equals
devrait).Pour autant que je le comprends, la réponse est simple:
==
compare les références d'objet..Equals
compare le contenu de l'objet.String
les types de données agissent toujours comme une comparaison de contenu.J'espère que j'ai raison et qu'il a répondu à votre question.
la source
J'ajouterais que si vous transformez votre objet en chaîne, cela fonctionnera correctement. C'est pourquoi le compilateur vous donnera un avertissement disant:
la source
object expr = XXX; if (expr == "Energy") { ... }
, le côté gauche étant de typeobject
compilation, le compilateur doit utiliser la surchargeoperator ==(object, object)
. Il vérifie l'égalité de référence. Si cela donneratrue
oufalse
peut être difficile à prévoir en raison de l' internement de chaînes . Si vous savez que le côté gauche estnull
de type ou de typestring
, lancez le côté gauche surstring
avant de l'utiliser==
.Étant donné que la version statique de la
.Equal
méthode n'a pas été mentionnée jusqu'à présent, je voudrais l'ajouter ici pour résumer et comparer les 3 variantes.où
MyString
est une variable qui vient d'ailleurs dans le code.Informations de fond et pour résumer:
En Java, utiliser
==
pour comparer les chaînes ne doit pas être utilisé. Je mentionne cela au cas où vous auriez besoin d'utiliser les deux langues et aussi pour vous faire savoir que l'utilisation==
peut également être remplacée par quelque chose de mieux en C #.En C #, il n'y a pas de différence pratique pour comparer des chaînes en utilisant la méthode 1 ou la méthode 2 tant que les deux sont de type chaîne. Cependant, si l'un est nul, l'un est d'un autre type (comme un entier), ou l'un représente un objet qui a une référence différente, alors, comme le montre la question initiale, vous pouvez rencontrer que la comparaison du contenu pour l'égalité peut ne pas retourner ce que vous vous attendez.
Solution suggérée:
Étant donné que l'utilisation
==
n'est pas exactement la même chose que.Equals
lors de la comparaison, vous pouvez utiliser la méthode statique String.Equals à la place. De cette façon, si les deux côtés ne sont pas du même type, vous comparerez toujours le contenu et si l'un est nul, vous éviterez l'exception.C'est un peu plus à écrire, mais à mon avis, plus sûr à utiliser.
Voici quelques informations copiées de Microsoft:
Paramètres
a
ChaîneLa première chaîne à comparer, ou
null
.b
ChaîneLa deuxième chaîne à comparer, ou
null
.Retour
Boolean
true
si la valeur dea
est la même que la valeur deb
; autrement,false
. Si les deuxa
et leb
sontnull
, la méthode retournetrue
.la source
Tout 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 de chiffres. 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 valeurs d'objet {int} -
la source
Je suis un peu confus ici. Si le type d'exécution de Content est de type chaîne, alors == et Equals doivent renvoyer true. Cependant, étant donné que cela ne semble pas être le cas, le type d'exécution du contenu n'est pas une chaîne et appeler Equals dessus fait une égalité référentielle et cela explique pourquoi Equals ("Energy Attack") échoue. Cependant, dans le second cas, la décision quant à 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 le contenu fournit une conversion implicite en chaîne.
la source
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 la façon dont nous sommes arrivés à la
string
valeur. Pour illustrer:La sortie est:
la source
Ajout d'un point de plus à la réponse.
.EqualsTo()
La méthode vous permet de comparer la culture et la casse.la source
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 lesquels les deux types peuvent être convertis. Si le compilateur trouve une telle surcharge, il l'utilisera. Sinon, si les deux types sont tous les deux des types de référence et qu'ils ne sont pas des classes non liées (soit il peut s'agir d'une interface, soit de classes liées), le compilateur considérera==
comme un opérateur de comparaison de référence. Si aucune des conditions ne s'applique, la compilation échouera.Notez que certaines autres langues utilisent des jetons distincts pour les deux opérateurs de vérification d'égalité. Dans VB.NET, par exemple, le
=
jeton est utilisé dans les expressions uniquement pour l'opérateur de vérification d'égalité surchargeable etIs
est utilisé comme opérateur de test de référence ou de test nul. Un à utiliser=
sur un type qui ne remplace pas l'opérateur de vérification d'égalité échouera, de même que la tentative d'utilisationIs
à d'autres fins que le test d'égalité ou de nullité de référence.(*) Les types ne surchargent généralement l'égalité que pour la comparaison avec eux-mêmes, mais il peut être utile pour les types de surcharger l'opérateur d'égalité pour la comparaison avec d'autres types particuliers; par exemple,
int
aurait pu (etfloat
à mon humble avis aurait dû mais pas) défini un opérateur d'égalité à comparer , de sorte que 16777217 ne se rapporterait pas égal à 16777216f. En l'état, étant donné qu'aucun opérateur de ce type n'est défini, C # promeut leint
tofloat
en l'arrondissant à 16777216f avant que l'opérateur de vérification d'égalité ne le voit; cet opérateur voit alors deux nombres à virgule flottante égaux et les signale comme égaux, ignorant l'arrondi qui a eu lieu.la source
3
comme étant égal3.0f
. Si nous demandons au programmeur de dire ce qui est prévu dans tous les cas, il n'y a aucun danger de comportement par défaut conduisant à des résultats inattendus, car il n'y a pas de comportement par défaut.Des réponses et des exemples vraiment géniaux!
Je voudrais juste ajouter la différence fondamentale entre les deux,
Avec ce concept à l'esprit, si vous travaillez sur un exemple (en regardant le type de référence à gauche et à droite, et en vérifiant / sachant si le type a effectivement == opérateur surchargé et égal à étant remplacé), vous êtes certain d'obtenir la bonne réponse .
la source
Lorsque nous créons un objet, l'objet est divisé en deux parties, l'une est le contenu et l'autre fait référence à ce contenu.
==
compare à la fois le contenu et la référence;equals()
compare uniquement le contenuhttp://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq
la source
a
etb
sont tous deux des références de chaîne, le résultat dea == b
ne dépend pas du fait que les références pointent vers le même objet.==
L'opérateur == peut être utilisé pour comparer deux variables de toute nature, et il compare simplement les bits .
Remarque: il y a plus de zéros sur le côté gauche de l'int, mais nous ne nous en soucions pas ici.
int a (00000011) == octet b (00000011)
Rappelez-vous que l'opérateur == ne se soucie que du modèle des bits de la variable.
Utilisez == si deux références (primitives) font référence au même objet sur le tas.
Les règles sont les mêmes que la variable soit une référence ou une primitive.
a == c est vrai a == b est faux
le motif binaire est le même pour a et c, ils sont donc égaux en utilisant ==.
Égal():
Utilisez la méthode equals () pour voir si deux objets différents sont égaux .
Tels que deux objets String différents qui représentent tous les deux les personnages de "Jane"
la source
object a = 3; object b = 3; Console.WriteLine(a == b);
. La sortie est fausse, même si les modèles binaires des valeurs sont les mêmes. Les types d'opérandes importent également. La raison pour laquelle nous "ne nous soucions pas" du nombre différent de zéros dans votre exemple est qu'au moment où nous appelons l'opérateur égal, le nombre de zéros est en fait le même , en raison de la conversion implicite.La seule différence entre Equal et == réside dans la comparaison des types d'objets. dans d'autres cas, tels que les types de référence et les types de valeurs, ils sont presque identiques (les deux sont une égalité bit à bit ou les deux une égalité de référence).
objet: égal à: égalité bit à bit ==: égalité de référence
chaîne: (égal et == sont les mêmes pour la chaîne, mais si l'une des chaînes a changé en objet, le résultat de la comparaison sera différent) Égale: égalité bit à bit ==: égalité bit à bit
Voir ici pour plus d'explications.
la source