Warum gibt> = false zurück, wenn == true für Nullwerte zurückgibt?


78

Ich habe zwei Variablen vom Typ int? (oder Nullable <int>, wenn Sie so wollen). Ich wollte einen Vergleich größer als oder gleich (> =) für die beiden Variablen durchführen, aber wie sich herausstellt, gibt dies false zurück, wenn beide Variablen null sind, während der Operator == offensichtlich true zurückgibt.

Kann mir jemand erklären, warum das logisch ist, weil die semantische Definition des Operators> = das Wort "oder" enthält?


1
Können Sie den Code posten, der dieses seltsame Verhalten erzeugt?
Android Eve

12
Eigentlich würde ich fragen, ob es angemessen ist, dass == true zurückgibt. Ich halte das überhaupt nicht für angemessen. Wie können zwei Variablen, deren Wert unbekannt ist, als gleich zertifiziert werden?
Charles Bretana

2
@Charles, weil, wenn sie aus dem gleichen abgeglichenen sind Typ (zB int?), dann ihr Wert ist bekannt. null.
Moo-Juice

3
@ Moo-Saft, nicht in meiner Welt ... Wenn dein Name null ist, würdest du darauf antworten? null ist nicht dasselbe wie "null". Es gibt einen alten Film namens "Mein Name ist niemand" ("Wer hat das Glas zerbrochen, Kinder?" ---- "Niemand") Also wer ist "Niemand"? In der realen Welt (außerhalb der Code-Interna) bedeutet null, dass der Wert unbekannt ist. Der Datenstrukturwert ist möglicherweise bekannt (es ist Null), aber die reale Problemdomänenentität / der Wert, den die Variable darstellen soll, ist Nicht bekannt ..
Charles Bretana

2
@ Charles, liebe die Analogie!. Aber wer hat das Glas nicht zerbrochen?
Moo-Juice

Antworten:


97

Es gab eine große Debatte über diese Kuriosität, als das Feature ursprünglich in C # 2.0 entwickelt wurde. Das Problem ist, dass C # -Benutzer daran gewöhnt sind, dass dies sinnvoll ist:

if(someReference == null)

Wenn Sie die Gleichheit auf nullbare Werttypen erweitern, haben Sie folgende Möglichkeiten.

  1. Die nullbare Gleichheit wird wirklich aufgehoben . Wenn einer oder beide Operanden null sind, ist das Ergebnis weder wahr noch falsch, sondern null. In diesem Fall können Sie entweder:

    • a) Machen Sie es illegal, in einer ifAnweisung eine Gleichheit vom Typ nullbarer Werte zu haben , da die ifAnweisung einen Bool benötigt, keinen nullbaren Bool. Fordern Sie stattdessen alle zur Verwendung auf, HasValuewenn sie mit null vergleichen möchten. Das ist ausführlich und irritierend.

    • b) Konvertieren Sie automatisch null in false. Der Nachteil dabei ist, dass x==nullfalse zurückgegeben wird, wenn x null ist. Dies ist verwirrend und wirkt dem Verständnis der Benutzer von Nullvergleichen mit Referenztypen entgegen.

  2. Die nullbare Gleichheit wird nicht aufgehoben. Die nullbare Gleichheit ist entweder wahr oder falsch, und der Vergleich mit null ist eine Nullprüfung. Dies macht die nullbare Gleichheit mit der nullbaren Ungleichung unvereinbar.

Keine dieser Entscheidungen ist offensichtlich richtig; Sie alle haben Vor- und Nachteile. VBScript wählt zum Beispiel 1b. Nach langen Diskussionen entschied sich das C # -Design-Team für # 2.


Wie ist die nullbare Gleichheit nicht mit der nullbaren Ungleichung in Wahl 2 vereinbar?
MCS

3
@MCS: Genau so, wie es die Frage überhaupt motiviert. == kann wahr sein, wenn <= falsch ist.
Eric Lippert

@Eric: Danke - ich dachte, 'Ungleichung' bezieht sich nur auf! =, Was tatsächlich mit == übereinstimmt. Ich wusste nicht, dass es sich um einen mathematischen Begriff handelt: en.wikipedia.org/wiki/Inequality_(mathematics) .
MCS

1
Nun, die andere Frage (die Sie nicht angesprochen haben) ist das, was zu tun ist, wenn Sie versuchen , zu tun <, <=, =>, oder >wenn einer der Operanden ist null. In C # lautet die Antwort return false. In der Scala / Java- StringKlasse lautet die Antwort: a werfen NullPointerException.
Ken Bloom

3
@Brian: Warum sollten die Operatoren dann überhaupt nullbare Typen zulassen? Wenn sie immer den Nullwert des nullbaren Typs verwenden, können Sie den Operator genauso gut nur für die nicht nullbaren Typen definieren und den Benutzer veranlassen, die Konvertierung in den nicht nullbaren Typ einzufügen, da dies erforderlich ist tun, um die Ausnahme zu beseitigen.
Eric Lippert

59

Weil Gleichheit getrennt von Vergleichbarkeit definiert wird.
Sie können testen x == null, x > nullist aber bedeutungslos. In C # wird es immer falsch sein.


1
+1: Hier ist der MSDN-Link msdn.microsoft.com/en-us/library/2cf62fcy.aspx , aber leider haben sie vergessen, das Verhalten der Vergleichsoperatoren bei 2 Nullen zu erklären (sie haben nur Gleichheit erwähnt) ...
digEmAll

3
Ja, aber der Operator ist größer oder gleich. Ich sehe die Wahrheitstabelle, aber ich würde eher dem OP zustimmen,> = ist größer oder gleich, wenn null == null wahr ist, sollte null> = null auch wahr sein. Ich denke, wir kalkulieren es nur auf Implementierung und Benutzerfreundlichkeit, um die == Null-Prüfungen beizubehalten.
BlackICE

2
@ David, siehe Erics Antwort: "Keine dieser Entscheidungen ist offensichtlich richtig." Wenn ein Typ jedoch gleichwertig, aber nicht vergleichbar ist, >=wird er im Allgemeinen einfach nicht definiert.
Henk Holterman

11

Eine andere Art, '> =' zu beschreiben, ist: Nicht weniger als. Keine Erwähnung von Gleichen. Sobald einer der Operanden in einem Nichtgleichheitstest Null ist, ist das Ergebnis ebenfalls unbekannt (ist Null). Wenn Sie jedoch wissen möchten, ob beide Operanden Null sind, ist Null == Null ein vernünftiger Test (sollte zu true führen). Die Beseitigung des Ungleichheitsteils des Operators macht den Unterschied.

Das folgende Codebeispiel von http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx#sectionToggle4 fasst zusammen, wie C # Null behandelt:

int? num1 = 10;   
int? num2 = null;   
if (num1 >= num2)   
{   
    Console.WriteLine("num1 is greater than or equal to num2");   
}   
else   
{   
    // This clause is selected, but num1 is not less than num2.   
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");   
}   

if (num1 < num2)   
{   
    Console.WriteLine("num1 is less than num2");   
}   
else   
{   
    // The else clause is selected again, but num1 is not greater than   
    // or equal to num2.   
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");   
}   

if (num1 != num2)   
{   
    // This comparison is true, num1 and num2 are not equal.   
    Console.WriteLine("Finally, num1 != num2 returns true!");   
}   

// Change the value of num1, so that both num1 and num2 are null.   
num1 = null;   
if (num1 == num2)   
{   
    // The equality comparison returns true when both operands are null.   
    Console.WriteLine("num1 == num2 returns true when the value of each is null");   
}   

/* Output:   
 * num1 >= num2 returned false (but num1 < num2 also is false)   
 * num1 < num2 returned false (but num1 >= num2 also is false)   
 * Finally, num1 != num2 returns true!   
 * num1 == num2 returns true when the value of each is null   
 */   

Das ist ein interessantes mentales Modell. Abschnitt §1.4 der C # -Spezifikation nennt diese Operatoren jedoch kleiner als oder gleich und größer als oder gleich
Conrad Frix

3
@Conrad Dies zeigt nur die Probleme bei der Übersetzung einer Programmiersprache (in diesem Fall C #) ins Englische. IMHO, wann immer Nulls Figur in der Logik, man braucht mit einem Tri-State - Ergebnis (wahr, falsch, unbekannt) zu beschäftigen. Jeder Ausdruck, an dem Null beteiligt ist, sollte zu unbekannt führen, mit der einzigen Ausnahme, Null == xdass es sich um einen expliziten Test für unbekannt handelt, der entweder wahr oder falsch ist.
NealB

@NealB: Tatsächlich besagt die Spezifikation, dass> = und <= bedeuten, was Sie von ihnen erwarten würden - Abschnitt §7.10 macht deutlich, dass die Operation 'x op y' für <= und> = gleich sein soll. zu oder größer als / kleiner als, wie man erwarten würde.
nicodemus13

2

>=arbeitet mit einem numerischen Wert; welche null ist nicht.

Sie können den Operator überladen>= , um das zu liefern, was Sie für einen bestimmten Typ wünschen.


es arbeitet mit Null-Typen, es gibt false zurück
BlackICE

Es behandelt Null-Typen, ja ... Semantik dessen, was wir als "operiert" definieren werden. Defensive Codierung; Ist es null, dann tun Sie x gegenüber der Behandlung von null als Literalwert, wenn Sie während der Auswertung Entscheidungen treffen.
Aaron McIver

Sie können Operatoren normalerweise nicht überladen, da Sie sie nur in ihren eigenen Klassen definieren können. In diesem Fall benötigen Sie also Zugriff auf Nullable<T>den Code.
ANeves denkt, SE ist böse

0

NULL ist nicht Null (numerischer oder binärer Wert), eine Zeichenfolge mit der Länge Null oder leer (Zeichenwert). Jeder Vergleichsoperator gibt also immer false zurück. Lesen Sie hier mehr darüber


8
Die Datenbank NULL ist nicht C # null. Darüber hinaus sind Vergleichsoperatoren für C # -Nullwerttypen ein seltsames Tier, das nicht unbedingt den üblichen Regeln für Nullvergleiche folgt.
Joren

3
Die Antwort ist immer noch richtig, nur der Link ist falsch. msdn.microsoft.com/en-us/library/2cf62fcy.aspx#sectionToggle4
unholysampler

5
@unholy: Die Antwort ist falsch und vor allem basiert sie auf falschen Überlegungen.
Joren

0

Welche Werte würden Sie erwarten?

null == null true

null> = null false

null> null false

null <= null false

null <null false

null! = null false

1 == null false

1> = null false

1> null false

1 <= null false

1 <null false

1! = Null true aka! (1 == null)


0

> = bedeutet nur "größer oder gleich", wenn es auf diese genau definierte Weise verwendet wird. Bei Verwendung in einer Klasse mit überladenen Operatoren bedeutet dies alles, was der Klassenentwickler möchte. Wenn es auf eine stringähnliche Klasse angewendet wird, bedeutet dies möglicherweise "gleich oder höher sortieren" oder "gleich lang oder länger".


0

Da ein standardmäßig intnicht null sein kann und sein Wert auf gesetzt 0wird int, erwartet der Operator von> und <, der für den Typ erstellt wurde, dass er mit valuesund nicht mit arbeitet nulls.

siehe meine Antwort auf eine ähnliche Frage , wo ich schrieb einige Möglichkeiten , um Griff nullable intmit den less <und greater >Betreibern https://stackoverflow.com/a/51507612/7003760

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.