Qual è la "migliore" implementazione canonica di Equals() per i tipi di riferimento?

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

  •  09-06-2019
  •  | 
  •  

Domanda

L'implementazione di Equals() per i tipi di riferimento è più difficile di quanto sembri.La mia attuale implementazione canonica è questa:

public bool Equals( MyClass obj )
{
  // If both refer to the same reference they are equal.
  if( ReferenceEquals( obj, this ) )
    return true;

  // If the other object is null they are not equal because in C# this cannot be null.
  if( ReferenceEquals( obj, null ) )
   return false;

   // Compare data to evaluate equality    
   return _data.Equals( obj._data );
}

public override bool Equals( object obj )
{
  // If both refer to the same reference they are equal.
  if( ReferenceEquals( obj, this ) )
    return true;

  // If the other object is null or is of a different types the objects are not equal. 
  if( ReferenceEquals( obj, null ) || obj.GetType() != GetType() )
    return false;

  // Use type-safe equality comparison
  return Equals( (MyClass)obj );
}

public override int GetHashCode()
{
  // Use data's hash code as our hashcode  
  return _data.GetHashCode();
}

Penso che questo copra tutti i casi limite (eredità e simili), ma potrei sbagliarmi.Che cosa ne pensate?

È stato utile?

Soluzione

Tempo fa ho scritto una guida abbastanza completa sull'argomento.Per cominciare, le tue implementazioni uguali dovrebbero essere condivise (ad es.il sovraccarico che prende un oggetto dovrebbe passare a quello che prende un oggetto fortemente tipizzato).Inoltre devi considerare cose come il tuo oggetto che dovrebbe essere immutabile a causa della necessità di sovrascrivere GetHashCode.Maggiori informazioni qui:

http://gregbeech.com/blog/implementing-object-equality-in-dotnet

Altri suggerimenti

Meglio sperare che this._data non sia null se è anche un tipo di riferimento.

public bool Equals( MyClass obj )
{
    if (obj == null) {
        return false;
    }
    else {
        return (this._data != null && this._data.Equals( obj._data ))
                         || obj._data == null;
    }
}

public override bool Equals( object obj )
{
    if (obj == null || !(obj is MyClass)) {
        return false;
    }
    else {
        return this.Equals( (MyClass)obj );
    }
}

public override int GetHashCode() {
    return this._data == null ? 0 : this._data.GetHashCode();
}

Per quanto riguarda l'ereditarietà, penso che dovresti lasciare che il paradigma OO faccia la sua magia.

Nello specifico, il GetType() check dovrebbe essere rimosso, potrebbe interrompere il polimorfismo su tutta la linea.

Sono d'accordo con chakrit, oggetti di tipo diverso dovrebbero poter essere semanticamente uguali se hanno gli stessi dati o ID.

Personalmente utilizzo quanto segue:

    public override bool Equals(object obj)
    {
        var other = obj as MyClass;
        if (other == null) return false;

        return this.data.Equals(other.data);
    }

Dipende se stai scrivendo un tipo valore o un tipo riferimento.Per un tipo di valore ordinabile, consiglio questo:Uno snippet di codice per Visual Studio 2005 che implementa un tipo di valore di base aderente alle linee guida per la progettazione del framework

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top