web-dev-qa-db-fra.com

Quelle est la différence entre == et Equals () pour les primitives en C #?

Considérons ce code:

int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge);  //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();

int et short sont des types primitifs, mais une comparaison avec == renvoie true et une comparaison avec Equals renvoie false.

Pourquoi?

179
Mohammad Zargarani

Réponse courte:

L'égalité est compliquée.

Réponse détaillée:

Les types de primitives remplacent la base object.Equals(object) et retournent la valeur true si la boîte object est de même type et de valeur. (Notez que cela fonctionnera également pour les types nullable; les types nullable non null sont toujours associés à une instance du type sous-jacent.)

Puisque newAge est un short, sa méthode Equals(object) ne renvoie true que si vous passez un court-circuit court avec la même valeur. Vous passez une boîte int dans une boîte, donc elle renvoie false.

En revanche, l'opérateur == Est défini comme prenant deux int s (ou short s ou long s).
Lorsque vous l'appelez avec un int et un short, le compilateur convertira implicitement le short en int et comparera le résultat int s en valeur.

Autres moyens de le faire fonctionner

Les types primitifs ont également leur propre méthode Equals() qui accepte le même type.
Si vous écrivez age.Equals(newAge), le compilateur sélectionnera int.Equals(int) comme meilleure surcharge et convertira implicitement short en int. Il retournera ensuite true, puisque cette méthode compare simplement les int s directement.

short a également une méthode short.Equals(short), mais int ne peut pas être converti implicitement en short, vous ne l'appelez donc pas.

Vous pouvez le forcer à appeler cette méthode avec un casting:

Console.WriteLine(newAge.Equals((short)age)); // true

Ceci appellera short.Equals(short) directement, sans boxe. Si age est supérieur à 32767, une exception de dépassement de capacité sera générée.

Vous pouvez également appeler la surcharge short.Equals(object), mais explicitement passer un objet encadré afin qu'il ait le même type:

Console.WriteLine(newAge.Equals((object)(short)age)); // true

Comme l’alternative précédente, cela provoquera un débordement s’il ne rentre pas dans un short. Contrairement à la solution précédente, il encapsulera le short dans un objet, ce qui entraînera une perte de temps et de mémoire.

Code source:

Voici les deux méthodes Equals() du code source actuel:

    public override bool Equals(Object obj) {
        if (!(obj is Int16)) {
            return false;
        }
        return m_value == ((Int16)obj).m_value;
    }

    public bool Equals(Int16 obj)
    {
        return m_value == obj;
    }

Lectures complémentaires:

Voir Eric Lippert .

261
SLaks

Parce qu'il n'y a pas de surcharge pour short.Equals qui accepte un int. Par conséquent, cela s'appelle:

public override bool Equals(object obj)
{
    return obj is short && this == (short)obj;
}

obj n'est pas un short .. donc, il est faux.

55
Simon Whitehead

Pour les types de valeur, .Equals nécessite que les deux objets soient du même type et aient la même valeur, tandis que == _ teste simplement si les deux valeurs sont identiques.

Object.Equals
http://msdn.Microsoft.com/en-us/library/bsc2ak47 (v = vs.110) .aspx

12
wdosanjos

Lorsque vous passez int à short, vous transmettez object:

enter image description here Donc, ce pseudocode s'exécute:

return obj is short && this == (short)obj;
12
user1968030

== est utilisé pour vérifier une condition égale, il peut être considéré comme un opérateur (opérateur booléen), juste pour comparer 2 choses et ici le type de données importe peu car il y aurait un casting de type et Equals est également utilisé pour vérifier la condition égale, mais dans ce cas, les types de données doivent être identiques. N Equals est une méthode et non un opérateur.

Vous trouverez ci-dessous un petit exemple tiré de celui que vous avez fourni et qui clarifiera brièvement la différence.

int x=1;
short y=1;
x==y;//true
y.Equals(x);//false

dans l'exemple ci-dessus, X et Y ont les mêmes valeurs, à savoir 1, et lorsque nous utilisons ==, il retournera vrai, comme dans le cas de ==, le type court est converti en int par le compilateur et le résultat est donné.

et lorsque nous utilisons Equals, la comparaison est effectuée, mais la conversion de type n'est pas effectuée par le compilateur, donc la valeur false est renvoyée.

Les gars, s'il vous plaît laissez-moi savoir si je me trompe.

10
user2423959

Dans de nombreux contextes où un argument de méthode ou d'opérateur n'est pas du type requis, le compilateur C # tente d'effectuer une conversion de type implicite. Si le compilateur parvient à ce que tous les arguments satisfassent leurs opérateurs et leurs méthodes en ajoutant des conversions implicites, il le fera sans problème, même si dans certains cas (en particulier avec des tests d'égalité!) Les résultats peuvent être surprenants.

En outre, chaque type de valeur tel que int ou short décrit en fait à la fois un type de valeur et un type d’objet (*). Les conversions implicites existent pour convertir des valeurs en d'autres types de valeurs et pour convertir n'importe quel type de valeur en un type d'objet correspondant, mais les différents types d'objets ne sont pas implicitement convertibles l'un pour l'autre.

Si on utilise le == _ opérateur pour comparer un short et un int, le short sera converti implicitement en un int. Si sa valeur numérique était égale à celle du int, le int auquel il a été converti sera égal au int auquel il est comparé. Si on tente d'utiliser la méthode Equals sur le court métrage pour la comparer avec un int, la seule conversion implicite qui satisferait une surcharge de la méthode Equals serait la conversion en type d'objet correspondant à int. Quand on demande au short s'il correspond ou non à l'objet transmis, il s'aperçoit que l'objet en question est un int plutôt qu'un short et conclut donc qu'il ne peut pas peut-être être égal.

En général, même si le compilateur ne s'en plaint pas, il faut éviter de comparer des choses qui ne sont pas du même type; si l'on veut savoir si la conversion d'objets en une forme commune donnerait le même résultat, on devrait effectuer cette conversion de manière explicite. Considérons, par exemple,

int i = 16777217;
float f = 16777216.0f;

Console.WriteLine("{0}", i==f);

Il existe trois manières de comparer un int à un float. On peut vouloir savoir:

  1. La valeur float la plus proche de int correspond-elle à float?
  2. Est-ce que la partie entière du float correspond au int?
  3. Est-ce que int et float représentent la même valeur numérique.

Si on essaie de comparer directement int et float, le code compilé répondra à la première question; Que ce soit ce que le programmeur a prévu, cependant, sera loin d'être évident. Changer la comparaison en (float)i == f préciserait que le premier sens était voulu, ou (double)i == (double)f _ obligerait le code à répondre à la troisième question (et préciserait que c'était ce que l'on voulait).

(*) Même si la spécification C # concerne une valeur de type par ex. System.Int32 comme objet de type System.Int32, une telle vue est contredite par l'exigence qu'un code s'exécute sur une plate-forme dont les spécifications considèrent les valeurs et les objets comme habitant des univers différents. De plus, si T est un type de référence et que x est un T, une référence de type T devrait pouvoir faire référence à x. Ainsi, si une variable v de type Int32 détient un Object, une référence de type Object devrait pouvoir contenir une référence à v ou à son contenu. En fait, une référence de type Object pourrait pointer sur un objet contenant des données copiées à partir de v, mais pas sur v ni sur son contenu. Cela suggérerait que ni v ni son contenu ne soit réellement un Object.

6
supercat

Equals () est une méthode de System.Object Class
Syntaxe: Public bool virtuel Equals ()
Recommandation si nous voulons comparer l’état de deux objets, nous devons utiliser la méthode Equals ()

comme indiqué ci-dessus, les réponses == les opérateurs comparent les valeurs sont les mêmes.

S'il vous plaît ne vous trompez pas avec ReferenceEqual

Reference Equals ()
Syntaxe: public static bool ReferenceEquals ()
Détermine si l'instance d'objets spécifiés est de la même instance

5
Sugat Mankar

Ce que vous devez comprendre, c'est que faire == finira toujours par appeler une méthode. La question est de savoir si appeler == et Equals finissent par appeler/faire la même chose.

Avec les types de référence, == vérifiera toujours si les références sont les mêmes (Object.ReferenceEquals). Equals d'autre part peut être remplacé et peut vérifier si certaines valeurs sont égales.

EDIT: pour répondre à svick et ajouter un commentaire SLaks, voici du code IL

int i1 = 0x22; // ldc.i4.s ie pushes an int32 on the stack
int i2 = 0x33; // ldc.i4.s 
short s1 = 0x11; // ldc.i4.s (same as for int32)
short s2 = 0x22; // ldc.i4.s 

s1 == i1 // ceq
i1 == s1 // ceq
i1 == i2 // ceq
s1 == s2 // ceq
// no difference between int and short for those 4 cases,
// anyway the shorts are pushed as integers.

i1.Equals(i2) // calls System.Int32.Equals
s1.Equals(s2) // calls System.Int16.Equals
i1.Equals(s1) // calls System.Int32.Equals: s1 is considered as an integer
// - again it was pushed as such on the stack)
s1.Equals(i1) // boxes the int32 then calls System.Int16.Equals
// - int16 has 2 Equals methods: one for in16 and one for Object.
// Casting an int32 into an int16 is not safe, so the Object overload
// must be used instead.
4
user276648

== En primitive

Console.WriteLine(age == newAge);          // true

Dans la comparaison primitive, l'opérateur == se comporte assez clairement. En C #, il existe de nombreuses surcharges d'opérateur == disponibles.

  • chaîne == chaîne
  • int == int
  • uint == uint
  • long == long
  • beaucoup plus

Donc, dans ce cas, il n’ya pas de conversion implicite de int en short mais short en int est possible. Donc newAge est converti en int et une comparaison est effectuée, ce qui retourne true car les deux ont la même valeur. Donc, cela équivaut à:

Console.WriteLine(age == (int)newAge);          // true

. Equals () dans Primitive

Console.WriteLine(newAge.Equals(age));         //false

Ici, nous devons voir quelle est la méthode Equals (), en appelant Equals avec une variable de type courte. Donc, il y a trois possibilités:

  • Equals (objet, objet) // méthode statique de l'objet
  • Equals (object) // méthode virtuelle à partir d'objet
  • Equals (court) // Implémente IEquatable.Equals (court)

Le premier type n’est pas le cas ici car le nombre d’arguments est différent. Nous appelons avec un seul argument de type int. Troisième est également éliminé comme mentionné ci-dessus, la conversion implicite de int en short n'est pas possible. Donc, ici, le second type de Equals(object) est appelé. La short.Equals(object) est:

bool Equals(object z)
{
  return z is short && (short)z == this;
}

Donc ici la condition a été testée z is short Qui est fausse car z est un int, donc elle retourne fausse.

Voici l'article détaillé d'Eric Lippert

3
Zaheer Ahmed