Comparaison d’objets - bonnes pratiques
Ben voilà : vous avez deux objets en mains, X1 et X2, et vous vous demandez s’ils sont égaux… Ou s’il s’agit du même… Comment faites-vous ? Lire ci-dessous pour quelques pistes.
Il existe plusieurs façons de comparer deux objets :
if ( obj1 == obj2 )
if ( ReferenceEquals( obj1, obj2 ))
if ( obj1.Equals( obj2 )) // Version virtuelle de Equals()
if ( MonType.Equals( obj1, obj2 )) // Version statique de Equals()
Différences entre la version statique et la version virtuelle de Equals
MonType.Equals( obj1, obj2 )est équivalent àobj1.Equals( obj2 )avec toutefois une différence de taille : elle ne provoque pas d’exception lorsqueobj1est nul. En fait, cette méthode retournetruesiobj1etobj2sont nuls,falsesi un seul des deux paramètres est nul, et appelle la version virtuelle deEquals()pour les autres cas.
Comment comparer la référence de deux objets
Pour comparer la référence de deux objets (c’est-à-dire pour déterminer s’il s’agit du même objet), préférer
ReferenceEquals()au double égal (==). Raison : clareté. Cette méthode est en effet la seule qui compare toujours et exclusivement la référence de deux objets. Ainsi, le double égal (==) compare généralement la référence, mais pas toujours (ex.: sis1ets2sont des strings,s1 == s2compare le contenu des chaines et non leur référence). De même, la méthodeEquals()du typeobjectcompare bien la référence de deux objets, mais cette méthode est généralement redéfinie pour comparer des valeurs.À noter que
ReferenceEquals( null, null )retournetrue.
Comment comparer la valeur de deux objets
S’il s’agit de chaînes, utiliser le double égal (==). Autrement, utiliser
Equals()(après avoir redéfini cette méthode, voir plus bas) :
string s1, s2;
MonType m1, m2;
if ( s1 == s2 )
<Traitement>
if ( MonType.Equals( m1, m2 )) // Fonctionne si m1 et/ou m2 == null
<Traitement>
if ( m1.Equals( m2 )) // Attention : exception si m1 == null !!
<Traitement>
Comment redéfinir la méthode Equals()
Une bonne pratique consiste à redéfinir systématiquement cette méthode. Je ne compte plus le nombre de fois où, devant vérifier si un objet avait été modifié par un traitmeent, j’ai dû rouvrir une classe (souvent une classe de base) pour y redéfinir cette méthode.
Un exemple. Supposons que la classe
MonTypecontienne deux champs de type valeur (valeur1etvaleur2) ainsi que la référence à un objet (objet1). Supposons également queMonTypesoit dérivé deMonTypeDeBase. Voici une redéfinition possible de la méthode Equals() :
public override bool Equals( object obj )
{
MonType m = obj as MonType;
if ( m == null )
return false;
if ( ! base.Equals( m )) // Appelle MonTypeDeBase.Equals()
return false;
if ( this.valeurs1 != m.valeur1 ||
this.valeurs2 != m.valeurs2 ||
! this.objet1.Equals( m.objet1 ) ||
return false;return true;
}
À propos des types valeur
Les types valeur (structures,
int,double,DateTime, etc.) ne suivent pas les mêmes règles. Voici ce qu’il faut retenir :
- Toujours utiliser le double égal (==) pour comparer deux types valeurs.
ReferenceEquals()retourne toujours faux pour deux types valeurs (les deux valeurs sont temporairement converties en deux objets distincts pour cette comparaison - les deux références que reçoitReferenceEquals()sont donc toujours différentes).- Lorsqu’on compare deux structures avec un double égal (
struct1 == struct2), c’est bien le contenu des structures qui est comparé. Toutefois, si la structure contient des références, la comparaison ne s’étend pas au contenu des objets pointés par ces références.