web-dev-qa-db-fra.com

Opérateur de surcharge == versus Equals ()

Je travaille sur un projet C # sur lequel, jusqu'à présent, j'ai utilisé des objets et des usines immuables pour m'assurer que les objets de type Foo peuvent toujours être comparés pour égalité avec ==.

Foo les objets ne peuvent pas être modifiés une fois créés, et la fabrique renvoie toujours le même objet pour un ensemble d'arguments donné. Cela fonctionne très bien, et tout au long de la base de code, nous supposons que == fonctionne toujours pour vérifier l'égalité.

Maintenant, je dois ajouter des fonctionnalités qui introduisent un boîtier Edge pour lequel cela ne fonctionnera pas toujours. La chose la plus simple à faire est de surcharger operator == pour ce type, afin qu'aucun autre code du projet ne doive être modifié. Mais cela me semble être une odeur de code: surcharge operator == et non Equals semble juste bizarre, et je suis habitué à la convention que == vérifie l'égalité des références et Equals vérifie l'égalité des objets (ou quel que soit le terme).

Est-ce une préoccupation légitime, ou devrais-je simplement aller de l'avant et surcharger operator ==?

44
JSBձոգչ

Je crois que la norme est que pour la plupart des types, .Equals vérifie la similitude des objets et l'opérateur == vérifie l'égalité de référence.

Je pense que la meilleure pratique est que pour les types immuables, l'opérateur == devrait vérifier la similitude, ainsi que .Equals. Et si vous voulez savoir s’il s’agit bien du même objet, utilisez .ReferenceEquals. Voir la classe C # String pour un exemple de cela.

28
McKay

Il y a une grande différence entre surcharge== et prioritaire Égale.

Quand vous avez l'expression

if (x == y) {

La méthode qui sera utilisée pour comparer les variables x et y est décidée à compilation temps. Il s'agit d'une surcharge de l'opérateur. Le type utilisé lors de la déclaration de x et y est utilisé pour définir la méthode utilisée pour les comparer. Le type réel dans x et y (c'est-à-dire une sous-classe ou une implémentation d'interface) n'est pas pertinent. Considérer ce qui suit.

object x = "hello";
object y = 'h' + "Ello"; // ensure it's a different reference

if (x == y) { // evaluates to FALSE

et ce qui suit

string x = "hello";
string y = 'h' + "Ello"; // ensure it's a different reference

if (x == y) { // evaluates to TRUE

Cela démontre que le type utilisé pour déclarer les variables x et y est utilisé pour déterminer quelle méthode est utilisée pour évaluer ==.

Par comparaison, Equals est déterminé à runtime en fonction du type réel dans la variable x. Equals est une méthode virtuelle sur Object que d'autres types peuvent, et font, remplacer. Par conséquent, les deux exemples suivants ont tous les deux la valeur true.

object x = "hello";
object y = 'h' + "Ello"; // ensure it's a different reference

if (x.Equals(y)) { // evaluates to TRUE

et ce qui suit

string x = "hello";
string y = 'h' + "Ello"; // ensure it's a different reference

if (x.Equals(y)) { // also evaluates to TRUE
89
Samuel Neff

Ça sent vraiment. Lorsque vous surchargez ==, Vous devez vous assurer que Equals() et GetHashCode() sont également cohérents. Voir directives MSDN .

Et la seule raison pour laquelle cela semble OK, c'est que vous décrivez votre type comme immuable.

7
Henk Holterman

Pour les types immuables, je ne pense pas qu'il y ait quelque chose de mal à avoir == Surchargé pour prendre en charge l'égalité des valeurs. Je ne pense pas que je remplacerais == Sans remplacer Equals pour avoir la même sémantique cependant. Si vous remplacez == Et devez vérifier l'égalité de référence pour une raison quelconque, vous pouvez utiliser Object.ReferenceEquals(a,b).

Voir ceci article Microsoft pour quelques directives utiles

7
Mike Sackton

Exemple montrant comment implémenter cela selon directives MSFT (ci-dessous). Notez que lorsque vous remplacez Equals, vous devez également remplacer GetHashCode (). J'espère que cela aide les gens.

public class Person
{
    public Guid Id { get; private set; }

    public Person(Guid id)
    {
        Id = id;
    }

    public Person()
    {
        Id = System.Guid.NewGuid();
    }

    public static bool operator ==(Person p1, Person p2)
    {
        bool rc;

        if (System.Object.ReferenceEquals(p1, p2))
        {
            rc = true;
        }
        else if (((object)p1 == null) || ((object)p2 == null))
        {
            rc = false;
        }
        else
        {
            rc = (p1.Id.CompareTo(p2.Id) == 0);
        }

        return rc;
    }

    public static bool operator !=(Person p1, Person p2)
    {
        return !(p1 == p2);
    }

    public override bool Equals(object obj)
    {
        bool rc = false;
        if (obj is Person)
        {
            Person p2 = obj as Person;
            rc = (this == p2);
        }
        return rc;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}
7
John

Selon les meilleures pratiques de Microsofts, le résultat de la méthode Equals et la surcharge égal (==) devraient être les mêmes.

CA2224: Remplacer est égal à l'opérateur de surcharge est égal à

5
Ykok