2014-01-14 9 views
69

Warum dieser Code return true:Warum haben diese beiden Vergleiche unterschiedliche Ergebnisse?

new Byte() == new Byte() // returns true 

aber dieser Code gibt false zurück:

new Byte[0] == new Byte[0] // returns false 
+12

Siehe http://ericlippert.com/2014/01/15/inconsistent-equality/ –

+4

Ich bin überrascht, niemand gefunden Duplikate für diese Frage, da es sehr einfach ist ** Wert ** Typ Verse ** Referenz * * Frage eingeben. – P5Coder

+2

Ich bin noch mehr überrascht von der Anzahl der Ups, die es hat - 51 ab sofort. – P5Coder

Antwort

143

Da new Byte() Werttyp erzeugt, der durch Wert verglichen werden (standardmäßig es byte mit Wert zurück 0). Und new Byte[0] erstellt Array, das ein Referenztyp ist und durch Verweis verglichen wird (und diese beiden Instanzen des Arrays werden unterschiedliche Referenzen haben).

Siehe Value Types and Reference Types Artikel für Details.

44

Bytes sind value types in .NET, was bedeutet, dass der ==-Operator nur dann true zurückgibt, wenn die beiden Bytes den gleichen Wert haben. Dies ist auch bekannt als value equality.

Aber Arrays sind reference types in .NET, was bedeutet, dass der Operator == nur dann true zurückgibt, wenn sie sich auf dieselbe Array-Instanz im Speicher beziehen. Dies ist auch bekannt als reference equality or identity.

Beachten Sie, dass die == Operator kann für beide Referenz- und Werttypen überlastet werden. System.String zum Beispiel ist ein Referenztyp, aber der Operator == für Strings vergleicht jedes Zeichen im Array in der Reihenfolge. Siehe Guidelines for Overloading Equals() and Operator == (C# Programming Guide).

Wenn Sie testen möchten, ob die Arrays genau die gleichen Werte (in dieser Reihenfolge) enthalten sollten Sie überlegen, Enumerable.SequenceEqual statt == verwenden.

+1

Ich glaube, der Kern der Frage ist der Operator "==" und seine duale Natur. Diese Antwort deckt das klar ab. –

+1

Die richtigste Antwort, wenn auch nur für "standardmäßig" –

+0

Ich mag die Verwendung von "standardmäßig" für andere Referenztypen, aber ist es tatsächlich möglich, dieses Verhalten für Array-Typen zu ändern? –

10

Vergleichsreferenz tatsächlich vergleicht Zeigeradresse, die unterschiedlich sind, dass der Grund zurückkehrt falsch und in Wertadresse keine Rolle, es Wert vergleicht.

Compiler versuchen, Werttyp in Registern zu speichern, aber aufgrund begrenzter Registernummer erfolgt weiterer Speicher in Stack mit Werten [Reference], während Referenztyp im Stapel aber Wert ist, der eine Adresse der Speicheradresse in Heap enthält.

Vergleich hier vergleichen Sie den Wert in Stapel, die für beide gleiche, während im zweiten Fall Adressen des Heap sind, die unterschiedlich sind in ersten Fall ist.

reference

+5

Das ist eine ziemlich verwirrende Antwort. Der erste Teil sieht immer noch wie ein Referenzvergleich aus, weil Sie immer noch das Wort "Zeiger" verwenden. Die Verwendung der Grafik gegenüber nur Text ist auch nervig, weil es mir sehr schwer macht, sie zu bearbeiten, um die Antwort zu verbessern. –

+0

-1 für die Verewigung der "Werttypen sind im Stapel gespeichert" Mythos. Ich hätte es sehr wahrscheinlich gedacht, dass die Ergebnisse dieser zwei 'neuen Byte()' - Aufrufe wahrscheinlich in Registern gespeichert werden. –

+0

@Damen_The_Unbeliever Registerspeicher hängt von der Registerverfügbarkeit ab, ansonsten speichert er im Stack, in beiden Fällen ist der Wert gleich. –

1

Es ist eine Überlastung des == Operator in der beide Operanden-Typ sind byte und es umgesetzt wird, um den Wert jedes Bytes zu vergleichen; In diesem Fall haben Sie zwei Nullbytes, und sie sind gleich.

== Der Betreiber ist für Arrays nicht überlastet, so dass die Überlast object zwei Operanden verwendet, die in dem zweiten Fall (da Arrays vom Typ object sind), und dessen Umsetzung vergleicht die Verweise auf die beiden Objekte. Der Bezug auf die beiden Arrays ist unterschiedlich.

Es ist erwähnenswert, dass dies nichts (direkt) damit zu tun hat, dass byte ein Werttyp ist und Arrays Referenztypen sind.Der == Operator für byte hat Wert Semantik nur, weil es eine bestimmte Überlastung des Betreibers mit dieser Implementierung gibt. Wenn diese Überladung nicht existierte, dann würde keine Überladung sein, für die zwei Bytes gültige Operanden wären, und als solcher würde der Code überhaupt nicht kompilieren. Sie können dies leicht sehen, indem Sie eine benutzerdefinierte struct erstellen und zwei Instanzen davon mit dem Operator == vergleichen. Der Code wird nicht kompiliert, es sei denn, Sie geben Ihre eigene Implementierung von == für diese Typen ein.