loading

JohnnyBEHAGUE

Télécharger mon CV

==, Equals et ReferenceEquals, quelle différence ?

Quand on commence à développer, on se demande parfois comment comparer efficacement deux types en C# : ==, Equals ou encore ReferenceEquals, il existe plusieurs manière de comparer deux éléments, donc comment faire la différence ?

Avant d’aborder cet article, il faudrait savoir la différence entre les types valeurs (int, decimal, enums, etc.) et références (string, etc.). Je ferais peut être un article plus tard là dessus, mais pour l’instant d’autres développeurs plus compétents le font mieux que moi 🙂

Comme vous le savez, tout objet en C# dérive de la classe Object. A partir de ceci, deux méthodes seront à notre disposition :

A partir de là, nous avons déjà une base pour travailler.

ReferenceEquals

Si nous lisons la documentation, nous pouvons déjà voir que ReferenceEquals a pour signature public static bool, et que le développeur ne peut pas la réécrire dans des classes dérivées.

  • Si le type testé est de type valeur, alors on peut avoir des comportements bizarres (si on fait un test de référence sur la même valeur, on aura toujours false).
  • Si le type testé est string, alors on va tester la référence, mais on peut avoir un phénomène qui se produit appelé le  String Interning.
String chaine1 = "test"; String chaine2 = "test"; String.ReferenceEquals(chaine1, chaine2);

On aura … true. Comme les string sont immutable (donc impossible d’en modifier un sans en créer implicitement un autre en mémoire), une optimisation est faite à l’exécution lors de la création : si une même valeur de string existe en mémoire, on va pointer vers l’adresse mémoire de cette chaîne plutôt qu’en créer une autre, dans un souci d’optimisation.

En revanche, si le type testé est un autre type référence, on teste la référence.

Par curiosité, si on veut voir l’intérieur de la méthode, voilà ce qu’on a :

public class Object { public static bool ReferenceEquals (Object objA, Object objB) { return objA == objB; } }

Equals

Equals a en revanche pour signature public virtual bool : les développeurs peuvent réécrire la méthode Equals dans des classes dérivées.

  • Si le type testé est de type valeur, la méthode Equals testera l’égalité de valeur, et donc la méthode Equals prendra tout son sens.
  • Si le type testé est string, alors là aussi on va tester sa valeur.
  • Si le type testé est de type référence, la méthode Equals testera l’égalité de référence, et sera donc équivalente à ReferenceEquals, sauf si la méthode a été réécrite (c’est le cas de la classe String par exemple)

Pareil que précédemment, le code :

public class Object { public virtual Boolean Equals(Object obj) { if(this == obj) return true; return false; } }

Donc en gros, ReferenceEquals et Object sont intimement lié à l’opérateur ==… Mais que fait-il exactement? Nous allons le découvrir ensemble!

==

Tout d’abord, un petit passage dans la documentation!

Maintenant, parlons de cet opérateur, qui est un peu particulier. dans le sens où il prend le type de l’instance à gauche de l’opérateur, donc faites attention à l’ordre de vos tests!

De plus, deux choses à savoir :

  • Si l’instance actuelle est de type valeur ou est un string (type référence), l’opérateur == testera l’égalité de valeur
  • Si l’instance actuelle est de type référence autre que string, l’opérateur testera l’égalité de référence, à défaut d’être réécrit par le développeur.

Ce qui veut dire que si on a ce code :

String chaine1 = "test"; Object chaine4 = chaine1; chaine4 == chaine1;

chaine4 étant de type Object, on utilisera la méthode Object.ReferenceEquals plutôt que String.Equals : On aura une comparaison de référence, et non de valeur. D’ailleurs Visual Studio nous prévient (en tout cas dans la version 2010 que j’utilise au travail), en disant « Possibilité d’une comparaison de références involontaire ; pour obtenir une comparaison de valeurs, effectuez un cast de la partie gauche en type ‘string' ».

D’ailleurs, un point important pendant mes recherches avec ce flux Stack Overflow, et notamment la réponse de BlueMonkMN : le type String réécrit à la fois la méthode Equals et l’opérateur ==, pour qu’il agisse tel qu’un type valeur.

Concernant les sources de mes recherches, je vous invite bien sûr à consulter le flux Stack Overflow que je vous ai cité, ainsi que les autres qui traitent sur ce sujet, et à consulter le livre CLR by C# de Jeffrey Richter (ça deviendra vite une habitude), qui est une vraie Bible dorénavant pour moi. Mais aussi et plus simplement à faire vos tests par vous même! C’est le meilleur moyen de découvrir le comportement du Framework.

En espérant vous avoir aiguillé sur le choix de vos futurs tests, à bientôt!

Leave a comment