2010-08-12 9 views
14

Ich habe den folgenden Code:Zwei .NET-Objekte, die gleich sind nicht sagen, sie sind

object val1 = 1; 
object val2 = 1; 

bool result1 = (val1 == val2);//Equals false 
bool result2 = val1.Equals(val2); //Equals true 

Was ist mit dem nach oben? Ist der einzige Weg, um dies zu beheben mit .Equals() -Methode zu gehen?

+0

Die sagen, sie sind gleich, aber zwei verschiedene Instanzen –

+0

Dude, == und .Equals tun 2 verschiedene Dinge. == Der Operator überprüft, ob val1 und val2 den gleichen Speicherplatz belegen (Referenz). .Equals prüft auf Gleichheit der Inhalte. – Icemanind

+5

Sie können auch die statische Methode 'object.Equals (object, object)' verwenden, die zuerst versucht, die Objekte mit dem Operator '==' zu vergleichen, und dann die Methode 'object.Equals (object) ', wenn beide Parameter vorhanden sind nicht null. Der Grund, warum ich es vorschlage, ist, dass Sie nicht vor dem Aufruf von 'object.Equals (object, object) 'auf Null überprüfen müssen, während Sie dies tun, wenn Sie' object.Equals (object) 'aufrufen. –

Antwort

32

Der Operator == ist statisch, nicht virtuell, daher wird das Verhalten vom statischen Typ und nicht vom Laufzeittyp bestimmt. Die Standard Implementierung für == auf Objekte des Referenztyps ist, die Referenzen zu vergleichen (obwohl Typen ein anderes Verhalten implementieren können, z. B. string). Sie haben zwei verschiedene Objekte und sie haben nicht die gleiche Referenz, so dass == false zurückgibt.

Die Lösung, wie Sie darauf hinweisen, ist die Verwendung von Equals. Equals ist eine virtuelle Methode. Da value1 Laufzeittyp Int32 hat, rufen Sie am Ende Int32.Equals. sehen von .NET Reflector können Sie, dass die Umsetzung dieser ist wie folgt:

public override bool Equals(object obj) 
{ 
    return ((obj is int) && (this == ((int) obj))); 
} 

Mit anderen Worten, es wird geprüft, ob das Argument vom Typ int, und wenn ja, wirft sie und verwendet die ==, die für definiert ist int. Dies vergleicht die Werte der ganzen Zahlen.

Ist der einzige Weg, um dies zu beheben mit .Equals() -Methode zu gehen?

Eine Alternative ist, Ihre Objekte zu int werfen und dann == verwenden, ebenso wie die Implementierung von Int32.Equals tut.

+0

Dies scheint die einzig richtige Antwort zu sein (oder zumindest bin ich mir ziemlich sicher, dass Sie == on string verwenden können und es wie erwartet funktionieren lässt). –

+1

Okay, ich verstehe nicht, warum * Equals * hier funktioniert. Laut der Dokumentation http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx "Die Standardimplementierung von * Equals * unterstützt Referenzgleichheit für Referenztypen und bitweise Gleichheit für Werttypen. Referenzgleichheit bedeutet das Objekt Referenzen, die verglichen werden, beziehen sich auf das gleiche * Objekt *. " –

+0

@John C: Gute Frage. Ist meine aktualisierte Antwort klarer? –

10

Ja. == prüft auf Referenzgleichheit. Verwenden Sie Equals, wo Sie Inhalte vergleichen möchten.

Sie fragen sich vielleicht, warum dies bei Objekten so ist. Wenn Sie eine Ganzzahl (Werttyp) für eine Objektvariable festlegen, wird eine Operation namens boxing ausgeführt. Diese Operation umschließt den Werttyp in ein Objekt und stellt ihn auf den Heapspeicher und gibt eine Referenz zurück. Dies geschieht zweimal und Referenzen werden unterschiedlich (obwohl die Werte identisch sind).

1

Das ist, weil, wenn Sie sie zu Objekten umwandeln, sie zu Verweisen auf int Werte "umgewandelt" werden. Und die beiden Referenzen sind nicht gleich. Aber equals vergleicht die referenzierten Werte anstelle der Referenzen.

0

Zwei Objekte sind gleich, wenn sie auf denselben Speicherbereich zeigen.

val1 == val1; //Equals true 

Wie von tc gezeigt, können Sie einen Operator überlasten.

public static bool operator ==(Object a, Object b) 

Auf diese Weise das Verhalten des Betreibers == wird derjenige mit dieser Methode definiert sein.

Sie sollten auch den Operator != überladen, wenn Sie == überlasten.

+1

Es sei denn, es gibt eine Überlastung des Bedieners. –

+0

@tc korrigiert meine Anwsser. Vielen Dank. –

2

== überprüft, ob die beiden Objekte identisch sind. Sie sind nicht.Sie stellen die gleiche Nummer dar, sind jedoch an verschiedenen Speicherorten gespeichert.

Es ist wie zwei Äpfel zu vergleichen. Beide sind Äpfel und sehen gleich aus, aber sie sind verschiedene Objekte.

0

Wenn Sie nicht object verwenden, sondern eine benutzerdefinierte Klasse, können Sie die == außer Kraft setzen und! = Operatoren und sollte wahrscheinlich die IEqualityComparer<T> Schnittstelle

public static bool operator ==(MyType left, MyType right) 
{ 
    //code here, don't forget about NULLS when writing comparison code!!! 
} 

public static bool operator !=(MyType left, MyType right) 
{ 
    return !(left == right); 
} 

public bool Equals(MyType x, MyType y) 
{ 
    return (x == y); 
} 

public int GetHashCode(MyType obj) 
{ 
    return base.GetHashCode(); 
} 
0

Die CIL für Ihren Code-Boxen die beiden ganzen Zahlen implementieren und vergleicht die zwei Objekte, die aus dem Boxen (==) resultieren. Dieser Vergleich dient als Referenz.

.locals init ([0] object val1, 
      [1] object val2, 
      [2] bool result1, 
      [3] bool result2) 
    IL_0000: nop 
    IL_0001: ldc.i4.1 
    IL_0002: box  [mscorlib]System.Int32 
    IL_0007: stloc.0 
    IL_0008: ldc.i4.1 
    IL_0009: box  [mscorlib]System.Int32 
    IL_000e: stloc.1 
    IL_000f: ldloc.0 
    IL_0010: ldloc.1 
    IL_0011: ceq 
    IL_0013: stloc.2 
    IL_0014: ldloc.0 
    IL_0015: ldloc.1 
    IL_0016: callvirt instance bool [mscorlib]System.Object::Equals(object) 
    IL_001b: stloc.3 

Für die .Equals es Object.Equals aufruft, das Int32.Equals (virtueller Methodenaufruf auf Object) ruft:

public override bool Equals(object obj) 
{ 
    return ((obj is int) && (this == ((int) obj))); 
} 

Dies wirft in int und vergleicht die Werte als ganze Zahlen, Wert Typvergleich.