Pourquoi les expressions suivantes sont-elles différentes?
[1] (object)0 == (object)0 //false
[2] ((object)0).Equals((object)0) // true
En fait, je peux totalement comprendre [1] parce que probablement le runtime .NET sera box
l'entier et commencera à comparer les références à la place. Mais pourquoi est [2] différent?
short myShort = 0; int myInt = 0; Console.WriteLine("{0}{1}{2}", myShort.Equals(myInt), myInt.Equals(myShort), myInt == myShort);
Maintenant, comparez-le à la réalité. Votre prédiction était-elle correcte? Sinon, pouvez-vous expliquer l'écart?int16
akashort
Equals, puis regardez msdn.microsoft.com/en-us/library/ms173105.aspx . Je ne veux pas gâcher le puzzle d'Eric Lippert, mais il devrait être assez facile à comprendre une fois que vous aurez lu ces pages.((Integer)0)==((Integer)0)
true.IFormattable x = 0; bool test = (object)x == (object)x;
. Aucune nouvelle boxe n'est effectuée lorsque la structure est déjà dans une boîte.Réponses:
La raison pour laquelle les appels se comportent différemment est qu'ils se lient à des méthodes très différentes.
Le
==
cas sera lié à l'opérateur d'égalité de référence statique. Il y a 2 box indépendantsint
valeurs créées, elles ne sont donc pas la même référence.Dans le second cas, vous vous liez à la méthode d'instance
Object.Equals
. C'est une méthode virtuelle qui filtrera jusqu'àInt32.Equals
et qui vérifie un entier encadré. Les deux valeurs entières sont 0 et sont donc égalesla source
==
affaire n'appelle pasObject.ReferenceEquals
. Il produit simplement l'ceq
instruction IL pour effectuer une comparaison de référence.==
fait la même chose queReferenceEquals
(sur Object, de toute façon). C'est juste une optimisation interne du côté de MS pour éviter les appels de fonctions internes inutiles sur des fonctions souvent utilisées.bool operator ==(object x, object y);
bool operator !=(object x, object y);
Les opérateurs retournent le résultat de la comparaison des deux références pour l'égalité ou la non-égalité. Il n'est pas obligatoire que la méthodeSystem.Object.ReferenceEquals
soit utilisée pour déterminer le résultat. À @markmnl: Non, le compilateur C # n'est pas en ligne, c'est quelque chose que la gigue fait parfois (mais pas dans ce cas). Donc 280Z28 a raison, laReferenceEquals
méthode n'est pas réellement utilisée.Cat Whiskers; Dog Fido; IDog Fred;
(pour les interfaces non apparentéesICat
etIDog
et les classes non liéesCat:ICat
etDog:IDog
), les comparaisonsWhiskers==Fido
etWhiskers==34
serait légal (la première ne pouvait être vrai si Moustaches et Fido étaient tous deux nuls, le second ne pourrait jamais être vrai ). En fait, un compilateur C # rejettera les deux.Whiskers==Fred;
sera interdit s'ilCat
est scellé, mais autorisé s'il ne l'est pas.Lorsque vous transtypez la valeur int
0
(ou tout autre type de valeur) enobject
, la valeur est encadrée . Chaqueobject
conversion en produit une boîte différente (c'est-à-dire une instance d'objet différente). L'==
opérateur duobject
type effectue une comparaison de référence, il renvoie donc false car le côté gauche et le côté droit ne sont pas la même instance.D'autre part, lorsque vous utilisez
Equals
, qui est une méthode virtuelle, il utilise l'implémentation du type boxed réel, c'estInt32.Equals
-à- dire , qui renvoie true puisque les deux objets ont la même valeur.la source
L'
==
opérateur, étant statique, n'est pas virtuel. Il exécutera le code exact que leobject
défini par classe (`objet étant le type à la compilation des opérandes), qui effectuera une comparaison de référence, quel que soit le type d'exécution de l'un ou l'autre objet.La
Equals
méthode est une méthode d'instance virtuelle. Il exécutera le code défini dans le type d'exécution réel du (premier) objet, pas le code de laobject
classe. Dans ce cas, l'objet est unint
, donc il effectuera une comparaison de valeurs, car c'est ce que leint
type définit pour saEquals
méthode.la source
==
jeton représente en fait deux opérateurs, dont l'un est surchargeable et l'autre non. Le comportement du deuxième opérateur est très différent de celui d'une surcharge sur (objet, objet).La
Equals()
méthode est virtuelle.Par conséquent, il appelle toujours l'implémentation concrète, même lorsque le site d'appel est converti
object
.int
remplaceEquals()
pour comparer par valeur, vous obtenez donc une comparaison de valeur.la source
==
Utilisation:Object.ReferenceEquals
Object.Equals
compare la valeur.le
object.ReferenceEquals
méthode compare les références. Lorsque vous allouez un objet, vous recevez une référence contenant une valeur indiquant son emplacement mémoire en plus des données de l'objet sur le tas de mémoire.La
object.Equals
méthode compare le contenu des objets. Il vérifie d'abord si les références sont égales, tout comme object.ReferenceEquals. Mais ensuite, il fait appel aux méthodes Equals dérivées pour tester davantage l'égalité. Regarde ça:la source
Object.ReferenceEquals
se comporte comme une méthode qui utilise l'==
opérateur C # sur ses opérandes, l'opérateur d'opérateur d'égalité de référence C # (qui est représenté en utilisant des==
types d'opérandes pour lesquels aucune surcharge n'est définie) utilise une instruction spéciale plutôt que d'appelerReferenceEquals
. De plus,Object.ReferenceEquals
acceptera les opérandes qui ne pourraient correspondre que si les deux sont nuls, et acceptera les opérandes qui doivent être forcés de typeObject
et ne peuvent donc pas correspondre à quoi que ce soit, tandis que la version d'égalité de référence de==
refuserait de compiler une telle utilisation .L'opérateur C # utilise le jeton
==
pour représenter deux opérateurs différents: un opérateur de comparaison statiquement surchargeable et un opérateur de comparaison de référence non surchargeable. Lorsqu'il rencontre le==
jeton, il vérifie d'abord s'il existe une surcharge de test d'égalité applicable aux types d'opérande. Si tel est le cas, il invoquera cette surcharge. Sinon, il vérifiera si les types sont applicables à l'opérateur de comparaison de références. Si tel est le cas, il utilisera cet opérateur. Si aucun opérateur n'est applicable aux types d'opérande, la compilation échouera.Le code
(Object)0
ne se contente pas upcast unInt32
àObject
:Int32
, comme tous les types de valeur, représente en fait deux types, l' un qui décrit les valeurs et les lieux de stockage (tels que le zéro littéral), mais ne tire pas de quoi que ce soit, et l' un qui décrit tas d'objets et dérive deObject
; car seul ce dernier type peut être convertiObject
, le compilateur doit créer un nouvel objet de tas de ce dernier type. Chaque appel de(Object)0
crée un nouvel objet de tas, de sorte que les deux opérandes à==
sont des objets différents, chacun desquels, indépendamment, encapsule laInt32
valeur 0.La classe
Object
n'a aucune surcharge utilisable définie pour l'opérateur égal. Par conséquent, le compilateur ne pourra pas utiliser l'opérateur de test d'égalité surchargé et reviendra à l'utilisation du test d'égalité de référence. Parce que les deux opérandes==
font référence à des objets distincts, il sera signaléfalse
. La deuxième comparaison réussit car elle demande à une instance d'objet de tasInt32
si elle est égale à l'autre. Parce que cette instance sait ce que signifie être égale à une autre instance distincte, elle peut répondretrue
.la source
0
dans votre code, je suppose que cela crée un objet int dans le tas pour cela. Ce n'est pas une référence unique à une valeur statique zéro globale (comme la façon dont ils ont fait String.Empty pour éviter de faire une nouvelle chaîne vide seulement des objets pour initialiser de nouvelles chaînes) Je suis assez sûr que cela même0.ReferenceEquals(0)
retournera faux, puisque les deux sont 0sInt32
objets nouvellement créés .0.ReferenceEquals(0)
échouera parce que vous essayez d'appeler une méthode sur une constante de temps de compilation. il n'y a aucun objet pour le suspendre. Un int unboxed est une structure, stockée sur la pile. Mêmeint i = 0; i.ReferenceEquals(...)
ne fonctionnera pas. ParceSystem.Int32
que n'hérite PAS deObject
.System.Int32
est unstruct
, unstruct
estSystem.ValueType
, qui hérite lui-mêmeSystem.Object
. C'est pourquoi il existe uneToString()
méthode et uneEquals
méthode pourSystem.Int32
Object
, et c'est là que j'ai arrêté de m'inquiéter à ce sujet il y a longtemps. Il n'a jamais été nécessaire d'aller plus loin. AFAIK le CLR gère les deux types différemment, et spécialement. Ce n'est pas seulement un héritage.is
Cependant, c'est l' un des deux types de données. Je ne voulais tout simplement pas que quiconque lise ce commentaire et s'écarte si loin de la piste, y compris cette étrangeté à propos des chaînes vides qui ignore l'internement de chaînes.Les deux contrôles sont différents. Le premier vérifie l' identité , le second l' égalité . En général, deux termes sont identiques s'ils font référence au même objet. Cela implique qu'ils sont égaux. Deux termes sont égaux, si leurs valeurs sont identiques.
En termes de programmation, l'identité est généralement définie par l'égalité de référence. Si le pointeur vers les deux termes est égal (!), L'objet sur lequel il pointe est exactement le même. Cependant, si les pointeurs sont différents, la valeur des objets sur lesquels ils pointent peut toujours être égale. En C #, l'identité peut être vérifiée à l'aide du
Object.ReferenceEquals
membre statique , tandis que l'égalité est vérifiée à l'aide duObject.Equals
membre non statique . Puisque vous transtypez deux entiers en objets (ce qui est appelé "boxing", btw), l'opérateur==
deobject
effectue la première vérification, qui est par défaut mappéeObject.ReferenceEquals
et vérifie l'identité. Si vous appelez explicitement le membre non statiqueEquals
, la répartition dynamique entraîne un appel àInt32.Equals
, qui vérifie l'égalité.Les deux concepts sont similaires, mais pas identiques. Ils peuvent sembler déroutants pour le premier, mais la petite différence est très importante! Imaginez deux personnes, à savoir «Alice» et «Bob». Ils vivent tous les deux dans une maison jaune. Sur la base de l'hypothèse, qu'Alice et Bob vivent dans un quartier, où les maisons ne diffèrent que par leur couleur, ils pourraient tous deux vivre dans des maisons jaunes différentes. Si vous comparez les deux maisons, vous reconnaîtrez qu'elles sont absolument identiques, car elles sont toutes les deux jaunes! Cependant, ils ne partagent pas la même maison et donc leurs maisons sont égales , mais pas identiques . L'identité impliquerait qu'ils vivent dans la même maison.
Remarque : certaines langues définissent l'
===
opérateur pour vérifier l'identité.la source