in IEquatable l’implementazione è un controllo di riferimento necessario

Ho una class che IEquatable . È necessario eseguire un controllo di refrence in Equals() o è gestito nel framework?

 class Foo : IEquatable { int value; Bar system; bool Equals(Foo other) { return this == other || ( value == other.value && system.Equals(other.system) ); } } 

Nell’esempio sopra è this==other affermazione superflua o necessaria?

Aggiornamento 1

Capisco che ho bisogno di correggere il codice come segue:

  bool Equals(Foo other) { if( other==null ) { return false; } if( object.ReferenceEquals(this, other) ) { return true; } //avoid recursion return value == other.value && system.Equals(other.system); } 

Grazie per le risposte.

    Credo che sia necessario. Il controllo di riferimento è il primo, rapido passo che puoi eseguire quando si confrontano gli oggetti.

    Nell’esempio che hai fornito, assicurati di controllare che l’ altro non sia null prima di accedere ai suoi valori.

     bool Equals(Foo other) { if(other == null) return false; if(this == other) return true; // Custom comparison logic here. } 

    In genere è un’ottimizzazione – sarebbe una strana implementazione Equals che fallirebbe senza di essa. Pertanto non lo ritengo necessario, ma non lo è “nel contesto”. Sono un’ottimizzazione economica da raggiungere, quindi di solito vale la pena includerla.

    Nota che se stai sovraccaricando == , probabilmente dovresti usare object.ReferenceEquals per eseguire questi confronti.

    Stai attento. In realtà, lo scoraggerebbe fortemente dal momento che se si desidera sovraccaricare l’operatore == per il proprio tipo di Foo in termini di Equals (come di solito si fa nella mia esperienza) ci si ritroverà con una ricorsione infinita.

    Per illustrare cosa intendo, ecco un’implementazione comune di == in termini di Equals :

     public static bool operator ==(Foo x, Foo y) { // Will overflow the stack if Equals uses ==: return !ReferenceEquals(x, null) && x.Equals(y); } 

    Detto questo, posso concordare pienamente con la tesi di Jon che potrebbe essere opportuno utilizzare ReferenceEquals .

    Non è necessario nel senso che potrebbe non essere richiesto per la correttezza, ma il framework di certo non “si prende cura di esso”, quindi potrebbe essere utile inserirsi, in genere per motivi di prestazioni.

    Un punto: se l’implementazione è completata da EqualityComparer.Default , non inserisce il codice utente se uno o entrambi gli argomenti sono null , quindi in tal caso esegue qualche misura di controllo di riferimento (se non a ReferenceEquals(x, y) completo ReferenceEquals(x, y) ).

     public override bool Equals(T x, T y) { if (x != null) { return ((y != null) && x.Equals(y)); } if (y != null) { return false; } return true; } 

    Off-topic, ci sono diversi problemi di null-dereferencing nel tuo metodo di esempio ( other potrebbero essere null , this.system potrebbe essere null ).

    Scriverò il tuo metodo come qualcosa del tipo:

     public bool Equals(Foo other) { if(other == null) return false; if(other == this) return true; return value == other.value && EqualityComparer.Default.Equals(bar, other.bar) // You don't *have to* go down the EqualityComparer route // but you do need to make sure you don't dereference null. 

    }

    Ricorda inoltre di sovrascrivere GetHashCode ogni volta che scrivi i tuoi confronti di uguaglianza.

    Penso sia necessario controllare this == other , perché si definiscono i propri equals . Se non vuoi che sia controllato con il puntatore, scrivi il tuo IEquatable .

    IEquatable è un’interfaccia; l’implementazione spetta all’implementatore.

    Dal momento che stai implementando l’interfaccia, sei responsabile di tutti i comportamenti previsti come definiti dall’interfaccia.