103 votes

C# .Equals(), .ReferenceEquals() et l'opérateur ==

Ma compréhension de ces trois était:

  • .Equals() teste l'égalité des données (pour faute d'une meilleure description). .Equals() peut renvoyer True pour différentes instances du même objet, et c'est la méthode la plus couramment substituée.

  • .ReferenceEquals() teste si deux objets sont la même instance et ne peut pas être substitué.

  • == est le même que ReferenceEquals() par défaut, mais cela PEUT être substitué.

Mais C# station affirme:

Dans la classe object, les méthodes Equals et ReferenceEquals sont sémantiquement équivalentes, à l'exception que ReferenceEquals fonctionne uniquement avec des instances d'objet. La méthode ReferenceEquals est statique.

Maintenant je ne comprends pas. Est-ce que quelqu'un pourrait éclairer ma lanterne?

106voto

Ani Points 59747

La source de votre confusion semble être qu'il y a une faute de frappe dans l'extrait de C# station, qui devrait indiquer : "... sauf que la méthode Equals ne fonctionne que sur les instances d'objets. La méthode ReferenceEquals est statique."


Vous avez raison dans les grandes lignes concernant les différences de significations sémantiques de chacun (bien que "différentes instances du même objet" semble un peu confus, cela devrait probablement dire "différentes instances du même type") et sur ceux qui peuvent être remplacés.

_Si nous laissons cela de côté, traitons la dernière partie de votre question, c'est-à-dire comment ils fonctionnent avec des instances d'objets System.Object et des références System.Object (nous avons besoin des deux pour contourner la nature non polymorphe de ==). Ici, toutes les trois opérations fonctionneront de manière équivalente, mais avec une mise en garde : Equals ne peut pas être invoqué sur null.

Equals est une méthode d'instance qui prend un paramètre (qui peut être null). Puisqu'il s'agit d'une méthode d'instance (doit être invoquée sur un objet réel), elle ne peut pas être invoquée sur une référence null.

ReferenceEquals est une méthode statique qui prend deux paramètres, un ou les deux pouvant être null. Puisqu'elle est statique (non associée à une instance d'objet), elle ne lancera pas d'NullReferenceException dans toutes circonstances.

== est un opérateur, qui, dans ce cas (object), se comporte de manière identique à ReferenceEquals. Il ne lancera pas d'NullReferenceException non plus.

Pour illustrer :

object o1 = null;
object o2 = new object();

//Techniquement, ces devraient être object.ReferenceEquals pour plus de clarté, mais c'est redondant.
ReferenceEquals(o1, o1); //true
ReferenceEquals(o1, o2); //false
ReferenceEquals(o2, o1); //false
ReferenceEquals(o2, o2); //true

o1.Equals(o1); //NullReferenceException
o1.Equals(o2); //NullReferenceException
o2.Equals(o1); //false
o2.Equals(o2); //true_

27voto

Alastair Pitts Points 11677

Jetez un coup d'œil à cet article MSDN sur le sujet.

Je pense que les points pertinents sont :

Pour vérifier l'égalité de référence, utilisez ReferenceEquals. Pour vérifier l'égalité de valeur, utilisez Equals ou Equals.

Par défaut, l'opérateur == teste l'égalité de référence en déterminant si deux références indiquent le même objet, donc les types de référence n'ont pas besoin de mettre en œuvre l'opérateur == pour bénéficier de cette fonctionnalité. Lorsqu'un type est immuable, c'est-à-dire que les données contenues dans l'instance ne peuvent pas être modifiées, surcharger l'opérateur == pour comparer l'égalité de valeur au lieu de l'égalité de référence peut être utile car, en tant qu'objets immuables, ils peuvent être considérés comme identiques tant qu'ils ont la même valeur.

J'espère que cela vous aidera!

10voto

Luke Schafer Points 6250

Votre compréhension de .ReferenceEquals est correcte.

.Equals vérifie l'égalité des données pour les types de valeur, et l'égalité de la référence pour les types non-valeurs (objets généraux).

.Equals peut être remplacé pour les objets afin d'effectuer une forme de vérification de l'égalité des données.

EDIT : De plus, .ReferenceEquals ne peut pas être utilisé sur les types de valeur (enfin, il peut l'être, mais sera toujours faux).

3voto

sotonika Points 121

Envie d'ajouter mon grain de sel sur la comparaison avec "null".

  1. ReferenceEquals(objet, objet) est la même que "(objet)arg1 == arg2" (donc dans le cas des types de valeur, vous obtenez un boxing et cela prend du temps). Mais cette méthode est le seul moyen 100% sûr de vérifier votre argument pour null dans plusieurs situations, comme

    • a) avant d'appeler ses membres via l'opérateur .
    • b) vérifier le résultat de l'opérateur AS.
  2. \== et Equals(). Pourquoi je dis que ReferenceEquals est 100% sûr avec les vérifications de null ? Imaginez que vous écriviez des extensions génériques dans des bibliothèques de projets principaux, et disons que vous restreignez le type de paramètre générique à un type de domaine spécifique. Ce type peut introduire l'opérateur "==" - maintenant ou plus tard (et croyez-moi, j'en ai vu beaucoup, cet opérateur peut avoir une logique très "étrange", surtout en ce qui concerne les objets de domaine ou de persistance). Vous essayez de vérifier votre argument pour null avant d'appeler une opération de membre dessus. Surprise, vous POUVEZ avoir un NullRef ici. Parce que l'opérateur == est presque identique à Equals() - très personnalisé et très imprévisible. Il y a cependant une différence, qu'il faut prendre en compte - si vous ne restreignez pas votre paramètre générique à un type personnalisé (== peut être utilisé uniquement si votre type est une "classe"), l'opérateur == est le même que object.ReferenceEquals(..). L'implémentation de Equals est toujours utilisée à partir du type final, car c'est virtuel.

Donc ma recommandation est, lorsque vous écrivez vos propres types ou que vous dérivez de types bien connus, vous pouvez utiliser == pour vérifier null. Sinon, utilisez object.ReferenceEquals(arg, null).

1voto

Yola Points 2650

Dans la classe Object, .Equals implémente l'identité, pas l'égalité. Il vérifie si les références sont égales. Le code pourrait être comme ceci :

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

Lors de l'implémentation de .Equals dans votre classe, vous devriez appeler la méthode .Equals de la classe de base seulement si la classe de base n'est pas Object. Oui, c'est compliqué.

De plus, comme les classes dérivées peuvent remplacer .Equals et que vous ne pouvez pas l'appeler pour vérifier l'identité, Microsoft a ajouté la méthode statique .ReferenceEquals.

Si vous utilisez une classe, alors pour vous logiquement .Equals vérifie l'égalité et .ReferenceEquals vérifie l'identité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X