Betrachten Sie diesen Code:
int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge); //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();
Beide int
und short
sind primitive Typen, aber ein Vergleich mit ==
return true und ein Vergleich mit Equals
return false.
Warum?
Console.WriteLine(age.Equals(newAge));
Equals()
im Allgemeinen ist.Antworten:
Kurze Antwort:
Gleichheit ist kompliziert.
Detaillierte Antwort:
Primitive Typen überschreiben die Basis
object.Equals(object)
und geben true zurück, wenn das Feldobject
denselben Typ und Wert hat. (Beachten Sie, dass dies auch für nullfähige Typen funktioniert. Nicht null-nullbare Typen können immer mit einer Instanz des zugrunde liegenden Typs verknüpft werden.)Da
newAge
es sich um a handeltshort
, gibt dieEquals(object)
Methode nur dann true zurück, wenn Sie einen Boxed Short mit demselben Wert übergeben. Sie übergeben eine Boxint
, daher wird false zurückgegeben.Im Gegensatz dazu wird der
==
Operator so definiert, dass er zweiint
s (odershort
s oderlong
s) nimmt.Wenn Sie es mit einem
int
und einem aufrufenshort
, konvertiert der Compiler implizit dasshort
inint
und vergleicht die resultierendenint
s nach Wert.Andere Möglichkeiten, damit es funktioniert
Primitive Typen haben auch eine eigene
Equals()
Methode, die denselben Typ akzeptiert.Wenn Sie schreiben
age.Equals(newAge)
, wählt der Compilerint.Equals(int)
die beste Überladung aus und konvertiert implizitshort
inint
. Es wird dann zurückgegebentrue
, da diese Methode einfach dasint
s direkt vergleicht .short
hat auch eineshort.Equals(short)
Methode,int
kann aber nicht implizit konvertiert werdenshort
, sodass Sie sie nicht aufrufen.Sie könnten es zwingen, diese Methode mit einer Besetzung aufzurufen:
Dies wird
short.Equals(short)
direkt ohne Boxen aufgerufen . Wennage
größer als 32767 ist, wird eine Überlaufausnahme ausgelöst.Sie können die
short.Equals(object)
Überladung auch aufrufen , aber ein Boxobjekt explizit übergeben, damit es denselben Typ erhält:Wie bei der vorherigen Alternative wird dadurch ein Überlauf ausgelöst, wenn er nicht in eine passt
short
. Im Gegensatz zur vorherigen Lösung wird dasshort
Objekt in ein Objekt gepackt, wodurch Zeit und Speicher verschwendet werden.Quellcode:
Hier sind beide
Equals()
Methoden aus dem eigentlichen Quellcode:Weiterführende Literatur:
Siehe Eric Lippert .
quelle
long == int
,int
implizit nachlong
rechts konvertiert ?int age = 25;
anconst int age = 25;
, dann ändert sich das Ergebnis. Dies liegt daran, dass in diesem Fall eine implizite Konvertierung vonint
nachshort
vorhanden ist. Siehe Implizite Konvertierungen konstanter Ausdrücke .==
vergleicht Referenztypen nach Referenz. Für Werttypen und für Typen, die überladen sind==
, ist dies nicht der Fall.Weil es keine Überlastung dafür gibt
short.Equals
, akzeptiert einint
. Daher heißt dies:obj
ist keinshort
.. daher ist es falsch.quelle
Wenn Sie
int
anshort
's Equals übergeben, übergeben Sieobject
:Dieser Pseudocode läuft also:
quelle
Für Werttypen
.Equals
müssen die beiden Objekte vom gleichen Typ sein und denselben Wert haben, während==
nur geprüft wird, ob die beiden Werte gleich sind.Object.Equals
http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx
quelle
==
wird zum Überprüfen einer Gleichheitsbedingung verwendet, kann als Operator (boolescher Operator) betrachtet werden, nur um zwei Dinge zu vergleichen, und hier spielt der Datentyp keine Rolle, da ein Typ-Casting durchgeführt würde, undEquals
wird auch zum Überprüfen der Gleichheitsbedingung verwendet In diesem Fall sollten die Datentypen jedoch identisch sein. N Equals ist eine Methode, kein Operator.Im Folgenden finden Sie ein kleines Beispiel aus dem von Ihnen bereitgestellten Beispiel, das den Unterschied in Kürze verdeutlicht.
Im obigen Beispiel haben X und Y die gleichen Werte, dh 1, und wenn wir verwenden
==
, wird true zurückgegeben, da im Fall von==
der Short-Typ vom Compiler in int konvertiert wird und das Ergebnis angegeben wird.und wenn wir verwenden
Equals
, wird der Vergleich durchgeführt, aber das Typ-Casting wird nicht vom Compiler durchgeführt, so dass false zurückgegeben wird.Leute, bitte lasst es mich wissen, wenn ich falsch liege.
quelle
In vielen Kontexten, in denen eine Methode oder ein Operatorargument nicht vom erforderlichen Typ ist, versucht der C # -Compiler, eine implizite Typkonvertierung durchzuführen. Wenn der Compiler alle Argumente durch Hinzufügen impliziter Konvertierungen an seine Operatoren und Methoden anpassen kann, erfolgt dies ohne Beanstandung, auch wenn die Ergebnisse in einigen Fällen (insbesondere bei Gleichheitstests!) Überraschend sein können.
Ferner beschreibt jeder Werttyp wie
int
odershort
tatsächlich sowohl eine Art von Wert als auch eine Art von Objekt (*). Es gibt implizite Konvertierungen, um Werte in andere Arten von Werten zu konvertieren und um jede Art von Wert in die entsprechende Art von Objekt zu konvertieren, aber die verschiedenen Arten von Objekten sind nicht implizit ineinander konvertierbar.Wenn man den
==
Operator verwendet, um ashort
und an zu vergleichenint
,short
wird das implizit in a konvertiertint
. Wenn sein numerischer Wert gleich dem von warint
, entspricht der Wert ,int
mit dem er konvertiert wurde, dem,int
mit dem er verglichen wird. Wenn man versucht, dieEquals
Methode für den Kurzschluss zu verwenden, um sie mit einer zu vergleichenint
, wäre die einzige implizite Konvertierung, die eine Überladung derEquals
Methode befriedigen würde, die Konvertierung in den entsprechenden Objekttypint
. Wenn dasshort
gefragt wird, ob es mit dem übergebenen Objekt übereinstimmt, wird es feststellen, dass das fragliche Objektint
eher ein als ein ist,short
und daraus schließen, dass es unmöglich gleich sein kann.Obwohl sich der Compiler nicht darüber beschwert, sollte man im Allgemeinen vermeiden, Dinge zu vergleichen, die nicht vom gleichen Typ sind. Wenn man daran interessiert ist, ob die Konvertierung von Dingen in eine gemeinsame Form das gleiche Ergebnis liefern würde, sollte man eine solche Konvertierung explizit durchführen. Betrachten Sie zum Beispiel
Es gibt drei Möglichkeiten, wie man ein
int
mit einem vergleichen möchtefloat
. Man möchte vielleicht wissen:float
Wertint
demfloat
?float
übereinint
?int
undfloat
repräsentieren Sie den gleichen numerischen Wert.Wenn man versucht, ein
int
undfloat
direkt zu vergleichen , beantwortet der kompilierte Code die erste Frage; Ob der Programmierer dies beabsichtigt hat, ist jedoch alles andere als offensichtlich. Wenn Sie den Vergleich auf(float)i == f
ändern, wird klargestellt, dass die erste Bedeutung beabsichtigt war, oder(double)i == (double)f
der Code beantwortet die dritte Frage (und es wird klargestellt, dass dies beabsichtigt ist).(*) Selbst wenn die C # -Spezifikation einen Wert vom Typ betrachtet, z.
System.Int32
B. ein Objekt vom TypSystem.Int32
, wird einer solchen Ansicht die Anforderung widersprochen, dass ein Code auf einer Plattform ausgeführt wird, deren Spezifikation Werte und Objekte als Bewohner verschiedener Universen betrachtet. WennT
es sich um einen Referenztyp handelt undx
es sich um einen handeltT
,T
sollte sich eine Referenz vom Typ beziehen könnenx
. Wenn also eine Variablev
vom TypInt32
eine enthältObject
, sollte eine Referenz vom TypObject
eine Referenzv
oder deren Inhalt enthalten können. Tatsächlich könnte eine Referenz vom TypObject
auf ein Objekt verweisen, das Daten enthält, die von kopiert wurdenv
, jedoch nicht auf sichv
selbst oder dessen Inhalt. Das würde darauf hindeuten, dass wederv
noch sein Inhalt ist wirklich einObject
.quelle
the only implicit conversion which would satisfy an overload of the Equals method would be the conversion to the object type corresponding to int
Falsch. Im Gegensatz zu Java verfügt C # nicht über separate primitive und Boxed-Typen. Es wird geboxt,object
weil das die einzige andere Überlastung von istEquals()
.float
. Das Wirken von afloat
zu adouble
wird nicht auf magische Weise neue Präzision erzeugen.List<String>.Enumerator
und eines Heap-Objekts vom TypList<String>.Enumerator
identisch ist, aber die ECMA / CLI-Spezifikation sagt, dass sie unterschiedlich sind, und selbst wenn sie in C # verwendet werden, verhalten sie sich unterschiedlich.i
und vor dem Vergleichf
jeweils konvertiertdouble
würden, würden sie 16777217.0 und 16777216.0 ergeben, die als ungleich verglichen werden. Das Konvertiereni
float
würde 16777216.0f ergeben, verglichen mitf
.bool SelfSame<T>(T p) { return Object.ReferenceEquals((Object)p,(Object)p);}
. Der Boxed-Objekttyp, der einem Werttyp entspricht, kann den ParametertypReferenceEquals
über einen identitätserhaltenden Upcast erfüllen. Der Speicherorttyp erfordert jedoch eine nicht identitätserhaltende Konvertierung. Wenn Gießen einT
zuU
Ausbeuten einen Verweis auf etwas anderes als das OriginalT
zu mir, die nahe legen, dass einT
nicht wirklich einU
.Equals () ist eine Methode der System.Object- Klassensyntax
: Public virtual bool Equals ()
Empfehlung Wenn wir den Status von zwei Objekten vergleichen möchten, sollten wir die Equals () -Methode verwenden
wie oben angegeben Antworten == Operatoren vergleichen die Werte sind gleich.
Bitte verwechseln Sie nicht ReferenceEqual
Reference Equals ()
Syntax: public static bool ReferenceEquals ()
Bestimmt, ob die angegebene Objektinstanz zur selben Instanz gehört
quelle
Was Sie wissen müssen, ist, dass das Tun
==
immer eine Methode aufruft. Die Frage ist, ob anrufen==
undEquals
am Ende die gleichen Dinge anrufen / tun.Bei Referenztypen
==
wird immer zuerst geprüft, ob die Referenzen identisch sind (Object.ReferenceEquals
).Equals
Auf der anderen Seite kann überschrieben werden und prüfen, ob einige Werte gleich sind.BEARBEITEN: Um svick zu beantworten und den Kommentar von SLaks hinzuzufügen, hier ein IL-Code
quelle
int
s mit ==? Hinweis: Es gibt keineoperator ==
Methode fürInt32
, aber es gibt eine fürString
.==
finde es immer noch interessant zu erklären, dass dies nicht nur Magie bewirkt, sondern schließlich einfach eine Methode aufruft (die meisten Programmierer haben wahrscheinlich nie einen Operator implementiert / überschrieben). Vielleicht hätte ich Ihrer Frage einen Kommentar hinzufügen können, anstatt meine eigene Antwort hinzuzufügen. Fühlen Sie sich frei, Ihre zu aktualisieren, wenn Sie der Meinung sind, dass das, was ich gesagt habe, relevant ist.==
bei primitiven Typen nicht um einen überladenen Operator handelt, sondern um eine intrinsische Sprachfunktion, die mit demceq
IL-Befehl kompiliert wird .== Im Primitiven
Im primitiven Vergleich verhalten sich == Operatoren ziemlich offensichtlich. In C # sind viele == Operatorüberladungen verfügbar.
In diesem Fall erfolgt also keine implizite Konvertierung von
int
zushort
abershort
zuint
ist möglich. NewAge wird also in int konvertiert und es erfolgt ein Vergleich, der true zurückgibt, da beide den gleichen Wert haben. Es ist also gleichbedeutend mit:.Equals () in Primitive
Hier müssen wir sehen, was die Equals () -Methode ist. Wir rufen Equals mit einer kurzen Typvariablen auf. Es gibt also drei Möglichkeiten:
Der erste Typ ist hier nicht der Fall, da die Anzahl der Argumente unterschiedlich ist und wir nur ein Argument vom Typ int aufrufen. Drittens wird ebenfalls eliminiert, wie oben erwähnt. Eine implizite Umwandlung von int in short ist nicht möglich. Also hier wird der zweite Typ von
Equals(object)
genannt. Dasshort.Equals(object)
ist:Also hier wurde der Zustand getestet
z is short
die falsch ist, da z ein int ist und daher false zurückgibt.Hier ist ein ausführlicher Artikel von Eric Lippert
quelle