2014-04-23 23 views
8

In diesem folgenden Beispiel gibt die dritte Auswertung false, alle gut, aber das vierte Beispiel gibt true zurück.
Ich verstehe nicht ganz, wie das funktioniert jedoch standardmäßig Object.Equals vergleicht zwei Referenzen für Objekt Gleichheit, und sehen als a und b zeigen beide auf eine eindeutige Instanz einer Zeichenfolge, sollte dies false zurückgeben, was es im dritten Beispiel tut, aber nicht in der vierten.
Jetzt verstehe ich, warum es in dem zweiten Beispiel True zurückgibt, da die .Equals()-Methode in der String-Klasse überschrieben wird, aber im vierten Beispiel wird diese Zeichenfolge als ein Objekt umgewandelt.
Also würde es Object.Equals in diesem Fall nicht anrufen?Überschreiben Gleich und Typ Casting

static void Main() 
{ 
    // Create two equal but distinct strings 
    string a = new string(new char[] {'h', 'e', 'l', 'l', 'o'}); 
    string b = new string(new char[] {'h', 'e', 'l', 'l', 'o'}); 

    Console.WriteLine (a == b); // Returns true 
    Console.WriteLine (a.Equals(b)); // Returns true 

    // Now let's see what happens with the same tests but 
    // with variables of type object 
    object c = a; 
    object d = b; 

    Console.WriteLine (c == d); // Returns false 
    Console.WriteLine (c.Equals(d)); // Returns true 
} 

Antwort

10

Der Schlüssel Wörter ist "by default". string überschreibt object.Equals mit einer benutzerdefinierten Implementierung. Da object.Equals eine polymorphe Methode ist (virtual/override/etc), wird die am weitesten abgeleitete Implementierung verwendet, auch wenn die Variable (/ Ausdruck) object ist.

== ist jedoch nicht polymorph; Die verwendete Implementierung hängt vollständig vom Typ der Variablen (/ expression) ab. Da in diesem Fall der bekannte Typ object ist, ist der einzige verfügbare Vergleich die Referenzgleichheit.

Vielleicht noch kurz und bündig:

class Foo { 
    public override string ToString() { return "hi"; } 
} 
//... 
object obj = new Foo(); 
string s = obj.ToString(); // this is "hi" 

Dies ist das gleiche Prinzip: die abgeleitete Überlastung einer virtuellen Methode verwendet wird, unabhängig von der Art, die die Compiler über (object in diesem Fall) kennen.

+1

Richtig, also, auch wenn wir die Zeichenfolge in ein Objekt umwandeln, wird es immer noch die überschriebene Implementierung von '.Equals' aufrufen? –

+0

@OverlyÜberschüssig ja; das ist der Schlüsselpunkt des Polymorphismus; Hervorhebung: Operatoren wie '==' sind ** nicht ** polymorph –

0

Da Equals eine virtuelle Methode ist, überschreibt jede Klasse, die equals implementiert, automatisch das ursprüngliche equals, egal was passiert. Wenn Sie das object.Equals verwenden möchten, müssen Sie object.ReferenceEquals(a,b) verwenden.

Für weitere Informationen prüfen, wie virtuelle Methoden arbeiten, und wenn Sie es das Gefühl oben sind, wie vtables tatsächlich umgesetzt (was eigentlich ganz einfach ist, sobald Sie den Dreh raus)

1

Die Equals Methode ist virtuell, das heißt, selbst wenn es bei einer Referenz mit dem Typ object aufgerufen wird, wird es am Ende die Implementierung für den konkreten Typ der Instanz aufrufen.

Aus dem erzeugten IL: a.Equals(b) wird

IL_003C: ldloc.0  // a 
IL_003D: ldloc.1  // b 
IL_003E: callvirt System.String.Equals 

und c.Equals(d)

IL_0057: ldloc.2  // c 
IL_0058: ldloc.3  // d 
IL_0059: callvirt System.Object.Equals 

wird also beide sind virtuelle Anrufe auf einer Referenz vom Typ String und Objekt sind, und beide berufen sich auf die Equals Methode, nicht auf die Referenz, sondern auf die Instanz selbst.

Auf der anderen Seite wird a==b einen Aufruf der statischen Methode System.String.op_Equality

IL_002F: ldloc.0  // a 
IL_0030: ldloc.1  // b 
IL_0031: call  System.String.op_Equality 

während c==d nur

wird
IL_004D: ldloc.2  // c 
IL_004E: ldloc.3  // d 
IL_004F: ceq  

, ein Aufruf der check-equal IL Instruktion, die nur einfache Referenz tut Überprüfung.


Sie können auch überprüfen, ob die überschriebene Implementierung mit Code wie genannt wird:

class MyClass 
{ 
    public override bool Equals(object obj) 
    { 
     Console.WriteLine("My Class Equals is called"); 
     return true; 
    } 
} 

void Main() 
{ 
    object a = new MyClass(); 
    object b = new MyClass(); 
    Console.WriteLine (a.Equals(b)); 
} 

erhalten Sie folgende Ausgabe

My Class Equals is called 
True