Ich habe eine Bedingung in einer Silverlight - Anwendung , die zwei Strings vergleicht, aus irgendeinem Grund , wenn ich ==
es wieder falsch während .Equals()
kehrt wahr .
Hier ist der Code:
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}
Gibt es einen Grund, warum dies geschieht?
==
, aber Operatoren sind nicht polymorph. In diesem Code wird der==
Operator für den Typ aufgerufenobject
, der einen Identitätsvergleich anstelle eines Werts eins durchführt.==
Überladung basierend auf dem Typ der Operanden zur Kompilierungszeit. DasContent
Anwesen istobject
. Operatoren sind nicht virtuell, daher wird die Standardimplementierung von==
aufgerufen, um einen Vergleich der Referenzgleichheit zu ermöglichen. Bei Equals geht der Aufruf an die virtuelle Methodeobject.Equals(object)
.string
überschreibt diese Methode und führt einen ordinalen Vergleich des Zeichenfolgeninhalts durch. Siehe msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx und referencesource.microsoft.com/#mscorlib/system/string.cs,507 .==
Typobject
zur Kompilierungszeit und die rechte Seite den Typ zur Kompilierungszeit hat . Es wird jedoch eine Warnung zur Kompilierungszeit ausgegeben, dass dies unbeabsichtigt sein könnte. So lesen Sie die Kompilierung-Warnungen! Um das Problem zu beheben und weiterhin zu verwenden , werfen Sie die linke Seite auf . Wenn ich mich richtig erinnere, schlägt der Warnungstext genau das vor.string
operator ==(object, object)
==
string
Antworten:
Wenn
==
es für einen Ausdruck vom Typ verwendet wirdobject
, wird es in aufgelöstSystem.Object.ReferenceEquals
.Equals
ist nur einevirtual
Methode und verhält sich so, daher wird die überschriebene Version verwendet (die für denstring
Typ den Inhalt vergleicht).quelle
object
Typ (beachten Sie die Monospace-Schriftart) technisch als "Ausdruck des TypsSystem.Object
" gedacht . Es hat nichts mit dem Laufzeittyp der Instanz zu tun, auf die der Ausdruck verweist. Ich denke, die Aussage "Benutzerdefinierte Operatoren werden wievirtual
Methoden behandelt " ist äußerst irreführend. Sie werden wie überladene Methoden behandelt und hängen nur vom Kompilierungszeittyp der Operanden ab. Nachdem der Satz von benutzerdefinierten Operatorenkandidaten berechnet wurde, ist der Rest der Bindungsprozedur genau der Algorithmus zur Auflösung der Methodenüberladungvirtual
Methodenauflösung vom tatsächlichen Laufzeittyp einer Instanz abhängt, während dies bei der Auflösung von Operatorüberlastungen völlig ignoriert wird, und das ist in der Tat der springende Punkt meiner Antwort.Beim Vergleichen einer Objektreferenz mit einer Zeichenfolge (auch wenn sich die Objektreferenz auf eine Zeichenfolge bezieht) wird das spezielle Verhalten des
==
für die Zeichenfolgenklasse spezifischen Operators ignoriert.Normalerweise (wenn es sich nicht um Zeichenfolgen handelt) werden Werte
Equals
verglichen , während Objektreferenzen verglichen werden . Wenn sich zwei Objekte, die Sie vergleichen, auf dieselbe exakte Instanz eines Objekts beziehen, geben beide true zurück. Wenn jedoch eines denselben Inhalt hat und aus einer anderen Quelle stammt (eine separate Instanz mit denselben Daten), wird nur Equals verwendet return true. Wie in den Kommentaren erwähnt, ist die Zeichenfolge jedoch ein Sonderfall, da sie den Operator überschreibt , sodass beim reinen Umgang mit Zeichenfolgenreferenzen (und nicht mit Objektreferenzen) nur die Werte verglichen werden, selbst wenn es sich um separate Instanzen handelt. Der folgende Code veranschaulicht die subtilen Unterschiede im Verhalten:==
==
Die Ausgabe ist:
quelle
==
und.Equals
sind sowohl abhängig vom im tatsächlichen Typ definierten Verhalten als auch vom tatsächlichen Typ am Anrufort. Beides sind nur Methoden / Operatoren, die für jeden Typ und jedes vom Autor gewünschte Verhalten überschrieben werden können. Nach meiner Erfahrung ist es üblich, dass Benutzer.Equals
ein Objekt implementieren, den Operator jedoch nicht implementieren==
. Dies bedeutet, dass.Equals
tatsächlich die Gleichheit der Werte==
gemessen wird, während gemessen wird, ob es sich um dieselbe Referenz handelt oder nicht.Wenn ich mit einem neuen Typ arbeite, dessen Definition im Fluss ist, oder generische Algorithmen schreibe, finde ich die folgende Best Practice
Object.ReferenceEquals
direkt (im generischen Fall nicht erforderlich)EqualityComparer<T>.Default
In einigen Fällen, wenn ich der Meinung bin, dass die Verwendung von nicht
==
eindeutig ist, verwende ich explizitObject.Reference
Gleichheiten im Code, um die Mehrdeutigkeit zu beseitigen.Eric Lippert hat kürzlich einen Blog-Beitrag zum Thema verfasst, warum es in der CLR zwei Methoden der Gleichstellung gibt. Es ist die Lektüre wert
quelle
== Operator
Gleichungen
quelle
==
Operator kann für jeden Typ überladen werden, nicht nur für Zeichenfolgen. Das Beschreiben einer Sonderfallausnahme nur für Zeichenfolgen stellt die Semantik des Operators falsch dar. Es wäre genauer, wenn auch nicht besonders nützlich zu sagen: "Wenn Operanden Referenztypen sind, gibt sie true zurück, wenn sich die Operanden auf dasselbe Objekt beziehen, es sei denn, es liegt eine anwendbare Überladung vor. In diesem Fall bestimmt die Implementierung dieser Überladung das Ergebnis." ". Gleiches gilt fürEquals
die zusätzliche Komplikation, dass es sich um eine virtuelle Methode handelt, sodass ihr Verhalten sowohl überschrieben als auch überladen werden kann.Erstens gibt es einen Unterschied. Für Zahlen
Und für Streicher
In beiden Fällen
==
verhält sich nützlicher als.Equals
quelle
==
Operator als eine gute Sache betrachten würde. Sollte beispielsweise 16777216.0f gleich (int) 16777217, (doppelt) 16777217.0, beide oder keine sein? Vergleiche zwischen integralen Typen sind in Ordnung, aber Gleitkomma-Vergleiche sollten IMHO nur mit Werten durchgeführt werden, die explizit in übereinstimmende Typen umgewandelt werden. Der Vergleich von afloat
mit etwas anderem als afloat
oder adouble
mit etwas anderem als adouble
scheint mir ein wichtiger Codegeruch zu sein, der ohne Diagnose nicht kompiliert werden sollte.x == y
nicht bedeutetx/3 == y/3
(versuchenx = 5
undy = 5.0
)./
für die Ganzzahldivision als einen Fehler im Design von C # und Java. Pascalsdiv
und sogar VB.NETs` are much better. The problems with
== `sind jedoch schlimmer:x==y
undy==z
implizieren das nichtx==z
(betrachten Sie die drei Zahlen in meinem vorherigen Kommentar). Was die Beziehung betrifft, die Sie vorschlagen, selbst wennx
undy
beidefloat
oder beide sinddouble
,x.equals((Object)y)
bedeutet dies nicht, dass1.0f/x ==
1.0f / y` (wenn ich meine Druthers hätte, würde dies dies garantieren; auch wenn==
nicht zwischen positiv und null unterschieden wird,Equals
sollte).Soweit ich es verstehe, ist die Antwort einfach:
==
vergleicht Objektreferenzen..Equals
vergleicht den Objektinhalt.String
Datentypen verhalten sich immer wie ein Inhaltsvergleich.Ich hoffe ich bin richtig und es hat deine Frage beantwortet.
quelle
Ich würde hinzufügen, dass wenn Sie Ihr Objekt in eine Zeichenfolge umwandeln, es korrekt funktioniert. Aus diesem Grund gibt der Compiler eine Warnung aus:
quelle
object expr = XXX; if (expr == "Energy") { ... }
, da die linke Seite vom Typobject
Kompilierungszeit istoperator ==(object, object)
. Es prüft auf Referenzgleichheit. Ob dies aufgrund der String-Internierung gegeben isttrue
oderfalse
schwer vorherzusagen ist . Wenn Sie wissen, dass die linke Seite entweder vom Typ oder vom Typ ist , werfen Sie die linke Seite vor der Verwendung auf .null
string
string
==
Da die statische Version der
.Equal
Methode bisher nicht erwähnt wurde, möchte ich diese hier hinzufügen, um die 3 Variationen zusammenzufassen und zu vergleichen.wo
MyString
ist eine Variable, die von irgendwo anders im Code kommt.Hintergrundinfo und zum Sommer:
In Java sollte die Verwendung
==
zum Vergleichen von Zeichenfolgen nicht verwendet werden. Ich erwähne dies für den Fall, dass Sie beide Sprachen verwenden müssen und dass Sie dies auch wissen müssen==
in C # auch durch etwas Besseres ersetzt kann.In C # gibt es keinen praktischen Unterschied für den Vergleich von Zeichenfolgen mit Methode 1 oder Methode 2, solange beide vom Typ Zeichenfolge sind. Wenn jedoch einer null ist, einer von einem anderen Typ ist (wie eine Ganzzahl) oder einer ein Objekt darstellt, das eine andere Referenz hat, kann es sein, dass der Vergleich des Inhalts auf Gleichheit möglicherweise nicht das zurückgibt, was die erste Frage zeigt du erwartest.
Vorgeschlagene Lösung:
Da die Verwendung
==
nicht genau mit der Verwendung.Equals
beim Vergleichen von Dingen identisch ist , können Sie stattdessen die statische String.Equals- Methode verwenden. Auf diese Weise vergleichen Sie den Inhalt, wenn die beiden Seiten nicht vom selben Typ sind, und wenn eine Null ist, vermeiden Sie die Ausnahme.Es ist etwas mehr zu schreiben, aber meiner Meinung nach sicherer zu verwenden.
Hier sind einige Informationen, die von Microsoft kopiert wurden:
Parameter
a
StringDie erste zu vergleichende Zeichenfolge, oder
null
.b
StringDie zweite zu vergleichende Zeichenfolge oder
null
.Kehrt zurück
Boolean
true
wenn der Wert vona
der gleiche ist wie der Wert vonb
; sonst ,false
. Wenn beidesa
undb
sindnull
, gibt die Methode zurücktrue
.quelle
Nur als Ergänzung zu den bereits guten Antworten: Dieses Verhalten ist NICHT auf Strings oder den Vergleich verschiedener Zahlentypen beschränkt. Auch wenn beide Elemente vom Typ Objekt desselben zugrunde liegenden Typs sind. "==" wird nicht funktionieren.
Der folgende Screenshot zeigt die Ergebnisse des Vergleichs zweier Objektwerte {int}
quelle
Ich bin hier etwas verwirrt. Wenn der Laufzeittyp von Content vom Typ string ist, sollten sowohl == als auch Equals true zurückgeben. Da dies jedoch nicht der Fall zu sein scheint, ist der Inhaltstyp zur Laufzeit keine Zeichenfolge, und das Aufrufen von Equals führt zu einer referenziellen Gleichheit. Dies erklärt, warum Equals ("Energy Attack") fehlschlägt. Im zweiten Fall wird jedoch zur Kompilierungszeit die Entscheidung getroffen, welcher überladene == statische Operator aufgerufen werden soll, und diese Entscheidung scheint == (Zeichenfolge, Zeichenfolge) zu sein. Dies legt für mich nahe, dass Content eine implizite Konvertierung in einen String bietet.
quelle
Eine frühere Antwort von @BlueMonkMN hat eine andere Dimension. Die zusätzliche Dimension ist, dass die Antwort auf die Titelfrage von @ Drahcir, wie angegeben, auch davon abhängt, wie wir zu dem
string
Wert gekommen sind. Um zu zeigen:Die Ausgabe ist:
quelle
Hinzufügen eines weiteren Punktes zur Antwort.
.EqualsTo()
Methode bietet Ihnen die Möglichkeit, mit Kultur und Groß- und Kleinschreibung zu vergleichen.quelle
Das
==
Token in C # wird für zwei verschiedene Gleichheitsprüfungsoperatoren verwendet. Wenn der Compiler auf dieses Token stößt, prüft er, ob einer der verglichenen Typen eine Überladung des Gleichheitsoperators für die zu vergleichenden spezifischen Kombinationstypen (*) oder für eine Kombination von Typen implementiert hat, in die beide Typen konvertiert werden können. Wenn der Compiler eine solche Überlastung feststellt, wird er diese verwenden. Andernfalls betrachtet der Compiler==
einen Referenzvergleichsoperator , wenn die beiden Typen beide Referenztypen sind und keine nicht verwandten Klassen sind (entweder eine Schnittstelle oder verwandte Klassen) . Wenn keine der beiden Bedingungen zutrifft, schlägt die Kompilierung fehl.Beachten Sie, dass einige andere Sprachen separate Token für die beiden Gleichheitsprüfungsoperatoren verwenden. In VB.NET wird das
=
Token beispielsweise in Ausdrücken ausschließlich für den überladbaren GleichheitsprüfungsoperatorIs
verwendet und als Referenztest- oder Nulltestoperator verwendet. Eine Verwendung=
für einen Typ, der den Gleichheitsprüfungsoperator nicht überschreibt, schlägt fehl, ebenso wie der Versuch, sieIs
für einen anderen Zweck als das Testen der Referenzgleichheit oder der Nichtigkeit zu verwenden.(*) Typen überladen im Allgemeinen nur die Gleichheit zum Vergleich mit sich selbst, aber es kann für Typen nützlich sein, den Gleichheitsoperator zum Vergleich mit anderen bestimmten Typen zu überladen. hätte zum Beispiel
int
einen Gleichheitsoperator zum Vergleich mit definieren können (und IMHO hätte dies tun sollen, aber nicht)float
, so dass sich 16777217 nicht gleich 16777216f melden würde. Wie es ist, da eine solche Operator definiert ist, wird C # die Förderungint
auffloat
, um es zu 16777216f Runden vor dem Gleichheitsprüfung Bediener es sieht; Dieser Operator sieht dann zwei gleiche Gleitkommazahlen und meldet sie als gleich, ohne die Rundung zu kennen, die stattgefunden hat.quelle
3
gleich behandeln3.0f
. Wenn der Programmierer in jedem Fall angeben muss, was beabsichtigt ist, besteht keine Gefahr, dass das Standardverhalten zu unbeabsichtigten Ergebnissen führt, da kein Standardverhalten vorliegt.Wirklich tolle Antworten und Beispiele!
Ich möchte nur den grundlegenden Unterschied zwischen den beiden hinzufügen,
Unter Berücksichtigung dieses Konzepts erhalten Sie mit Sicherheit die richtige Antwort, wenn Sie ein Beispiel ausarbeiten (indem Sie den Referenztyp für die linke und rechte Hand betrachten und prüfen / wissen, ob der Typ tatsächlich == Operator überladen und Equals überschrieben hat) .
quelle
Wenn wir ein Objekt erstellen, besteht das Objekt aus zwei Teilen: dem Inhalt und dem Verweis auf diesen Inhalt.
==
vergleicht sowohl Inhalt als auch Referenz;equals()
vergleicht nur Inhaltehttp://www.codeproject.com/Articles/584128/Was ist der Unterschied zwischen den gleichen Folgen und Gl
quelle
a
undb
beide Zeichenfolgenreferenzen sind,a == b
hängt das Ergebnis von nicht davon ab, ob die Referenzen auf dasselbe Objekt verweisen.==
Der Operator == kann verwendet werden, um zwei Variablen beliebiger Art zu vergleichen, und vergleicht einfach die Bits .
Hinweis: Auf der linken Seite des Int befinden sich weitere Nullen, aber das interessiert uns hier nicht.
int a (00000011) == Byte b (00000011)
Denken Sie daran, dass der Operator == sich nur um das Muster der Bits in der Variablen kümmert.
Use == Wenn zwei Referenzen (Grundelemente) auf dasselbe Objekt auf dem Heap verweisen.
Die Regeln sind gleich, unabhängig davon, ob die Variable eine Referenz oder ein Grundelement ist.
a == c ist wahr a == b ist falsch
Das Bitmuster ist für a und c gleich, daher sind sie mit == gleich.
Gleich():
Verwenden Sie die Methode equals (), um festzustellen, ob zwei verschiedene Objekte gleich sind .
Zum Beispiel zwei verschiedene String-Objekte, die beide die Zeichen in "Jane" darstellen.
quelle
object a = 3; object b = 3; Console.WriteLine(a == b);
. Die Ausgabe ist falsch, obwohl die Bitmuster der Werte gleich sind. Die Arten der Operanden spielen ebenfalls eine Rolle. Der Grund, warum uns die unterschiedliche Anzahl von Nullen in Ihrem Beispiel "egal" ist, ist, dass zum Zeitpunkt des Aufrufs des Gleichheitsoperators die Anzahl der Nullen aufgrund der impliziten Konvertierung tatsächlich gleich ist.Der einzige Unterschied zwischen Equal und == besteht im Objekttypvergleich. In anderen Fällen, z. B. bei Referenztypen und Werttypen, sind sie nahezu gleich (entweder sind beide bitweise Gleichheit oder beide sind Referenzgleichheit).
Objekt: Gleich: bitweise Gleichheit ==: Referenzgleichheit
Zeichenfolge: (gleich und == sind für Zeichenfolge gleich, aber wenn eine der Zeichenfolgen in Objekt geändert wird, ist das Vergleichsergebnis unterschiedlich.) Gleich: bitweise Gleichheit ==: bitweise Gleichheit
Sehen Sie hier für weitere Erklärung.
quelle