Plus robuste Equals mise en œuvre pour les classes personnalisées pour l'égalité de valeur en C #

StackOverflow https://stackoverflow.com/questions/570560

  •  05-09-2019
  •  | 
  •  

Question

Dire que j'ai une classe Point2, et je veux mettre en œuvre ce qui suit Égale:

public override bool Equals ( object obj )

public bool Equals ( Point2 obj )

Ceci est du livre Effective C # 3:

public override bool Equals ( object obj )
{
    // STEP 1: Check for null
    if ( obj == null )
    {
        return false;
    }

    // STEP 3: equivalent data types
    if ( this.GetType ( ) != obj.GetType ( ) )
    {
        return false;
    }
    return Equals ( ( Point2 ) obj );
}

public bool Equals ( Point2 obj )
{
    // STEP 1: Check for null if nullable (e.g., a reference type)
    if ( obj == null )
    {
        return false;
    }
    // STEP 2: Check for ReferenceEquals if this is a reference type
    if ( ReferenceEquals ( this, obj ) )
    {
        return true;
    }
    // STEP 4: Possibly check for equivalent hash codes
    if ( this.GetHashCode ( ) != obj.GetHashCode ( ) )
    {
        return false;
    }
    // STEP 5: Check base.Equals if base overrides Equals()
    System.Diagnostics.Debug.Assert (
        base.GetType ( ) != typeof ( object ) );

    if ( !base.Equals ( obj ) )
    {
        return false;
    }

    // STEP 6: Compare identifying fields for equality.
    return ( ( this.X.Equals ( obj.X ) ) && ( this.Y.Equals ( obj.Y ) ) );
}

Est-ce une surpuissance?

Était-ce utile?

La solution

Soutenir l'égalité avec une hiérarchie d'héritage est difficile. Vous devez déterminer exactement ce que vous voulez dire. Avez-vous vraiment besoin d'héritage ici? Dans le cas contraire - si Point2 dérive directement de System.Object, et vous pouvez le rendre étanche, la vie devient un peu plus facile. Dans ce cas, j'utiliser:

public override bool Equals (object obj)
{
    return Equals(obj as Point2);
}

public bool Equals (Point2 obj)
{
    // STEP 1: Check for null if nullable (e.g., a reference type)
    // Note use of ReferenceEquals in case you overload ==.
    if (object.ReferenceEquals(obj, null))
    {
        return false;
    }

    // STEP 2: Check for ReferenceEquals if this is a reference type
    // Skip this or not? With only two fields to check, it's probably
    // not worth it. If the later checks are costly, it could be.
    if (object.ReferenceEquals( this, obj))
    {
        return true;
    }

    // STEP 4: Possibly check for equivalent hash codes
    // Skipped in this case: would be *less* efficient

    // STEP 5: Check base.Equals if base overrides Equals()
    // Skipped in this case

    // STEP 6: Compare identifying fields for equality.
    // In this case I'm using == instead of Equals for brevity
    // - assuming X and Y are of a type which overloads ==.
    return this.X == obj.X && this.Y == obj.Y;
}

Autres conseils

Pas vraiment - vous la comptabilité pour à peu près toutes les possibilités. Si ce code est pour autre chose qu'une application de zéro, vous devriez considérer les avantages de cette approche, car les erreurs logiques en raison du comportement étrange de l'égalité des objets sont douloureuses à déboguer.

On dirait à moi comme exactement ce que vous voulez. Ce bloc entier se résume à:

"si elle est la même instance exacte, return true. Si elles sont des instances distinctes avec les mêmes valeurs X et Y, return true. Tous les autres cas (null, différents types, différentes valeurs x / y) return false."

Son code certainement plus de Je veulent écrire pour un signe égal méthode. Il y a beaucoup de contrôles redondants tels que la vérification des ReferenceEquals et hashcodes (je sais que ces contrôles sont redondants parce que les dernières lignes de votre fonction permet de l'égalité structurelle). Mettre l'accent sur le code qui est simple et lisible.

public bool Equals(object o)
{
    Point2 p = o as Point2;
    if (o != null)
        return this.X == o.X && this.Y == o.Y;
    else
        return false;
}

Étant donné que votre méthode equals utilise l'égalité structurelle, assurez-vous substituez GetHashCode avec une mise en œuvre en fonction de vos domaines.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top