Alkampfer's Place

Il blog di Gian Maria Ricci
posts - 659, comments - 871, trackbacks - 80

My Links

News

Gian Maria Ricci Mvp Logo CCSVI in Multiple Sclerosis

English Blog

Tag Cloud

Article Categories

Archives

Post Categories

Image Galleries

I miei siti

Siti utili

Ancora sull’equals

In un precedente post si parla di eguaglianza, volevo fare una piccola precisazione perché in un commento ho detto una cosa un po' sbagliata e confusa rispondendo a Diego di getto, ho per questo cancellato il commento riprendendo in maniera più estesa e spero più chiara il discorso. Prendete il seguente snippet:

Object TO3 = "test";
Object TO4 = new StringBuilder().Append("test").ToString();
Console.WriteLine("TO3 == TO4 is {0}", TO3 == TO4);
Console.WriteLine("Object.Equals(TO3,TO4) is {0}"Object.Equals(TO3, TO4));
Console.WriteLine("Object.ReferenceEquals(TO3, TO4) is {0}"Object.ReferenceEquals(TO3, TO4));

Stampa false, true, false; di questi, il terzo false è chiaro dato che il ReferenceEquals() compara per riferimento e le due stringhe sono chiaramente istanze differenti, ma per l'operatore == e per Object.Equals() avere un risultato differente può generalmente causare apprensione :D. Per capire il perché di questo comportamento bisogna prima di tutto capire come è implementato Objects.Equals (Fatto tramite reflector):

public static bool Equals(object objA, object objB) {
   
if (objA == objB) {
      
return true;
   }
   
if ((objA != null) && (objB != null)) {
      
return objA.Equals(objB);
   }
   
return false;
}

Come potete vedere prima di tutto viene fatta la comparazione con == (comparazione per riferimento) e poi se falsa viene chiamato l'equal dell'oggetto, quindi utilizzando polimorfismo, e dunque si chiama nel nostro caso lo String.Equals(), per questa ragione il secondo risultato è true, perché le istanze sono differenti ma il contenuto è eguale. In sostanza Object.Equals effettua la comparazione con l'effettivo metodo Equals implementato dall'oggetto specifico.

A questo punto basta disassemblare con il reflector il metodo Object.ReferenceEquals() e notare che la sua implementazione è return (objA == objB), quindi l'operatore == base a tutti gli effetti è la stessa cosa del ReferenceEquals() da qui si capisce perché TO3 == TO4 è false.

Se non ci fidiamo prendiamo lo snippet precedente e vediamo come è tradotto in MSIL l'istruzione TO3 == TO4:

L_0021: ldloc.0
L_0022: ldloc.1
L_0023: ceq

In sostanza si caricano nello stack le istanze dei due oggetti e poi viene chiamato ceq, l'istruzione MSIL che controlla se due oggetti nello stack sono uguali. Questo accade perché il compilatore vede l'operatore == applicato a due Object, sa che object non fa overload dell'operatore == e quindi fa un confronto per riferimento. Differente è la situazione se avessimo utilizzato l'operatore == tra due stringhe, il compilatore avrebbe prima di tutto cercato un metodo statico String.op_Equality(), e trovandolo avrebbe chiamato quello invece di fare una comparazione per riferimento.

Ora questo può suonare strano perché significa che due oggetti possono risultare differenti con un confronto tramite operatore ==, ma essere nello stesso tempo uguali chiamando un Object.Equals(objA, objB), per questo bisogna fare molta attenzione al concetto di eguaglianza. Personalmente trovo infatti questa cosa un po' fuorviante e preferisco nelle mie classi che lo richiedono fare l'override del solo metodo Equals() e non creare nessun operatore ==, in questo modo so che nelle mie classi l'operatore == è sempre e comunque una comparazione per riferimento.

Alk.

Print | posted on martedì 16 ottobre 2007 17:32 | Filed Under [ .NET ]

Feedback

Gravatar

# re: Ancora sull’equals

Ah ,naturalmente per un discorso più corretto e sicuramente migliore del mio leggete il "clr via c#" di Richter pagg 145-147 :D Sicuramente il Richter è più chiaro ed esaustivo :D

Alk.
16/10/2007 17:36 | Gian Maria
Gravatar

# Il Muro di UGI mi delude sempre pi

Il Muro di UGI mi delude sempre pi
16/10/2007 20:55 | Technology Experience (Reborn)
Gravatar

# re: Ancora sull’equals

Ah, scusami Igor, è che dopo 12 ore di lavoro sono veramente stordito per non dire Rinco****, pensavo che fosse un tuo commento ad indicare che il mio post ti aveva cosi deluso dal mettere il commento, non mi ero accorto che era un pingback.....mamma mia come sono ridotto :D :D :D

voglio le ferieeee hahahah ciao a tuttiiiii

Alk.
16/10/2007 22:24 | Gian Maria
Gravatar

# re: Ancora sull’equals

"Personalmente trovo infatti questa cosa un po' fuorviante e preferisco nelle mie classi che lo richiedono fare l'override del solo metodo Equals() e non creare nessun operatore ==, in questo modo so che nelle mie classi l'operatore == è sempre e comunque una comparazione per riferimento."

Quoto tutto dalla prima all'ultima riga, il problema è che mentre in java questo è di fatto lo standard (nel senso che non esiste l'overload di ==, quindi le uguaglianze le fai sempre e comunque con equals) in .NET non sei mai sicuro di cosa faccia effettivamente ==.

Penso che la soluzione migliore sia di non fare mai l'overload di == e usare sempre Object.Equals e Object.ReferenceEquals nelle comparazioni byval e byref.
17/10/2007 12:37 | Diego Guidi
Gravatar

# re: Ancora sull’equals

Talvolta si rimpiange il C++ :D, scherzo. In realtà è che alcune cose dovevano purtroppo essere pensate da prima, come dice anche il richter, l'implementazione base di Object.Equals di istanza non è che sia un granche :(

Alk.
17/10/2007 17:02 | Gian Maria
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET