2012-11-14 5 views
11

Sto scrivendo alcuni test di unità e la seguente asserzione fallisce:Perché Assert.AreEqual() esegue il cast sull'oggetto prima di eseguire il confronto?

Assert.AreEqual(expected.Episode, actual.Episode); 

Se io chiamo questo, invece, riesce:

Assert.IsTrue(expected.Episode.Equals(actual.Episode)); 

ho dato per scontato che in ultima analisi, Assert.AreEqual() chiama il metodo per la Equals() digitare è dato, in questo caso Episode.Equals().

Tuttavia, sotto le coperte in Microsoft.VisualStudio.TestTools.UnitTesting.Assert ho trovato il seguente codice (decompilato da ReSharper):

public static void AreEqual<T>(T expected, T actual, string message, params object[] parameters) 
{ 
    if (object.Equals((object)expected, (object)actual)) 
     return; 
    Assert.HandleFail... 
} 

Ciò implica per me che il metodo AreEqual() è colata sia expected e actual a object per forzare l'utilizzo del metodo base Equals() anziché il sovraccarico che ho scritto nella classe Episode. Il metodo base controllerà semplicemente per vedere se i riferimenti sono gli stessi, che non sono.

Ho due domande:

  1. è la mia spiegazione in realtà corretto, o mi sono perso qualcosa?
  2. Perché il framework desidera forzare l'uso di object.Equals() anziché un sovraccarico di tale metodo?

Se è rilevante, qui è il mio metodo:

public bool Equals(Episode other) 
{ 
    return Number == other.Number && 
      CaseNote.Equals(other.CaseNote) && 
      Patient.Equals(other.Patient); 
} 
+0

Offtopic: quale versione di ReSharper può decompilare? – sll

+0

Non sono sicuro di quanto tempo ci sia stato ma almeno v5 nella mia esperienza ... la prima volta che F12 (vai alla dichiarazione) su un oggetto interno ti chiederà cosa vuoi fare; una delle opzioni è decompilare. C'è anche un decompilatore standalone gratuito da Jetbrains. –

+1

btw, il metodo mostrato è un * overload *, non un 'override'. –

risposta

6

Sta usando object.Equals(object,object), che si occupa di cose come:

  • sono la stessa di riferimento?
  • è uno o entrambi un riferimento null?

e poi va avanti da usare x.Equals(y)dopo ha gestito queste cose. Deve fonderli a objectperché questo è ciò che object.Equals(object,object) richiede. La trasmissione a object evita anche alcune complicazioni con Nullable<T> (perché una casella T? su null o su una casella regolare T).

Tuttavia, potrebbe anche essere stato implementato come:

if (EqualityComparer<T>.Default.Equals(expected,actual)) 
    return; 

che gestisce Nullable<T>, IEquatable<T>, struct vs class, e pochi altri scenari senza alcuna boxe.

Ma: l'implementazione corrente fa il lavoro, e la casella occasionale non è la fine del mondo (e: il pugilato non è nemmeno un problema se il tuo tipo è un class).

+0

Si noti che [il controllo di null mediante il cast sull'oggetto su 'Nullable ' ha un impatto sulle prestazioni che può essere evitato] (http://stackoverflow.com/q/12396457/50776) (non è colpa tua, attenzione). – casperOne

+0

@casperOne infatti, ecco perché * se lo stavo scrivendo * avrei usato 'EqualityComparer ', che ** non ** ne soffre. –

+0

Mentre questa risposta è corretta, non riesce a spiegare perché l'OP sta vedendo false quando si aspetta di vedere vero. Il problema principale qui è che ha implementato solo 'Equals (Episodio altro)' e non 'Equals (object other)'. – Servy

4

Nel codice è necessario ignorare anche Equals(object other) (e è necessario sostituire anche GetHashCode).

Basta aggiungere questo al vostro codice di

public bool Equals(Episode other) 
{ 
    return Number == other.Number && 
      CaseNote.Equals(other.CaseNote) && 
      Patient.Equals(other.Patient); 
} 

public override bool Equals(object other) 
{ 
    Episode castOther = other as Episode; 
    if(castOther == null) 
     return false; 
    return this.Equals(castOther); 
} 

public override int GetHashCode() 
{ 
    //TODO: Implement using the members you used in "Equals(Episode other)" 
    throw new NotImplmentedExecption(); 
} 

ricordare per GetHashCode se due oggetti sono uguali essi devono ritornano anche i codici di hash uguali. Ecco un rapido diagramma per aiutarti a visualizzare.

enter image description here

Si consiglia di verificare CaseNote e Patient per problemi simili.

+0

Grazie per la tua utile risposta. Mi rendo conto che questo * è * il motivo per cui il mio codice restituisce risultati diversi per le due affermazioni. –