In VB.NET passiert Folgendes :
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false") '' <-- I got this. Why?
End If
Aber in C # passiert Folgendes:
decimal? x = default(decimal?);
decimal? y = default(decimal?);
y = 5;
if (x != y)
{
Debug.WriteLine("true"); // <-- I got this -- I'm with you, C# :)
}
else
{
Debug.WriteLine("false");
}
Warum gibt es einen Unterschied?
default(decimal?)
wird 0 zurückgegeben, nichtnull
.null
If
Bedingungen muss nicht als Boolescher Wert ausgewertet werden ... uuuugh EDIT: DasNothing <> Anything = Nothing
führt also dazu,If
dass der negative / else-Weg eingeschlagen wird.Antworten:
VB.NET und C # .NET sind verschiedene Sprachen, die von verschiedenen Teams erstellt wurden, die unterschiedliche Annahmen zur Verwendung getroffen haben. in diesem Fall die Semantik eines NULL-Vergleichs.
Meine persönliche Präferenz ist die VB.NET-Semantik, die NULL im Wesentlichen die Semantik "Ich weiß es noch nicht" gibt. Dann der Vergleich von 5 mit "Ich weiß es noch nicht". ist natürlich "Ich weiß es noch nicht"; dh NULL. Dies hat den zusätzlichen Vorteil, dass das Verhalten von NULL in (den meisten, wenn nicht allen) SQL-Datenbanken gespiegelt wird. Dies ist auch eine Standardinterpretation (als die von C #) der dreiwertigen Logik, wie hier erläutert .
Das C # -Team hat unterschiedliche Annahmen darüber getroffen, was NULL bedeutet, was zu dem von Ihnen gezeigten Verhaltensunterschied führt. Eric Lippert schrieb einen Blog über die Bedeutung von NULL in C # . Per Eric Lippert: "Ich habe hier und hier auch über die Semantik von Nullen in VB / VBScript und JScript geschrieben. "
In jeder Umgebung, in der NULL-Werte möglich sind, ist es wichtig zu erkennen, dass das Gesetz der ausgeschlossenen Mitte (dh dass A oder ~ A tautologisch wahr ist) nicht mehr verwendet werden kann.
Aktualisieren:
A
bool
(im Gegensatz zu abool?
) kann nur die Werte TRUE und FALSE annehmen. Eine Sprachimplementierung von NULL muss jedoch entscheiden, wie sich NULL durch Ausdrücke ausbreitet. In VB geben die Ausdrücke5=null
und5<>null
BEIDE false zurück. In C # wird von den vergleichbaren Ausdrücken5==null
und5!=null
nur demzweitenersten [aktualisiert am 02.03.2014 - PG] false zurückgegeben. In JEDER Umgebung, die null unterstützt, muss der Programmierer jedoch die von dieser Sprache verwendeten Wahrheitstabellen und die Null-Weitergabe kennen.Aktualisieren
Eric Lipperts Blog-Artikel (in seinen Kommentaren unten erwähnt) zur Semantik finden Sie jetzt unter:
30. September 2003 - Eine ganze Menge Nichts
1. Oktober 2003 - Ein bisschen mehr über nichts
quelle
bool
kann nicht 3 Werte haben, nur zwei. Dasbool?
kann drei Werte haben.operator ==
undoperator !=
beide gebenbool
nicht zurückbool?
, unabhängig vom Typ der Operanden. Darüber hinaus kann eineif
Anweisung nur a akzeptierenbool
, nicht abool?
.5=null
und5<>null
ungültig. Und von5 == null
und5 != null
, sind Sie sicher, dass es die Sekunde ist, die zurückkehrtfalse
?Weil
x <> y
zurückNothing
statttrue
. Es ist einfach nicht definiert, dax
es nicht definiert ist. (ähnlich wie SQL null).Hinweis: VB.NET
Nothing
<> C #null
.Sie müssen den Wert von a auch
Nullable(Of Decimal)
nur vergleichen, wenn er einen Wert hat.Das obige VB.NET vergleicht also ähnlich (was weniger falsch aussieht):
Die VB.NET- Sprachspezifikation :
Beispielsweise:
quelle
Schauen Sie sich die generierte CIL an (ich habe beide in C # konvertiert):
C #:
Visual Basic:
Sie werden sehen, dass der Vergleich in Visual Basic Nullable <bool> zurückgibt (nicht bool, false oder true!). Und undefiniert in bool konvertiert ist falsch.
Nothing
im Vergleich zu allem, wasNothing
in Visual Basic immer falsch ist (es ist dasselbe wie in SQL).quelle
Das Problem, das hier beobachtet wird, ist ein Sonderfall eines allgemeineren Problems, nämlich dass die Anzahl der verschiedenen Definitionen der Gleichheit, die zumindest unter bestimmten Umständen nützlich sein können, die Anzahl der allgemein verfügbaren Mittel übersteigt, um sie auszudrücken. Dieses Problem wird in einigen Fällen durch die unglückliche Annahme verschlimmert, dass es verwirrend ist, unterschiedliche Mittel zum Testen der Gleichheit zu verwenden, um unterschiedliche Ergebnisse zu erzielen, und eine solche Verwirrung könnte vermieden werden, indem die verschiedenen Formen der Gleichheit nach Möglichkeit dieselben Ergebnisse liefern.
In der Realität ist die fundamentale Ursache für Verwirrung eine fehlgeleitete Annahme, dass die verschiedenen Formen der Gleichheits- und Ungleichheitsprüfung das gleiche Ergebnis liefern sollten, ungeachtet der Tatsache, dass unterschiedliche Semantiken unter verschiedenen Umständen nützlich sind. Aus arithmetischer Sicht ist es beispielsweise nützlich, solche zu haben,
Decimal
die sich nur in der Anzahl der nachfolgenden Nullen unterscheiden, die als gleich verglichen werden. Ebenso fürdouble
Werte wie positive Null und negative Null. Andererseits kann eine solche Semantik vom Caching- oder Internierungsstandpunkt aus tödlich sein. Nehmen wir zum Beispiel an, man hätte eineDictionary<Decimal, String>
solche,myDict[someDecimal]
die gleich sein solltesomeDecimal.ToString()
. Ein solches Objekt würde vernünftig erscheinen, wenn man viele hätteDecimal
Werte, die man in einen String konvertieren wollte und erwartete, dass es viele Duplikate geben würde. Wenn ein solches Caching zum Konvertieren von 12,3 m und 12,40 m gefolgt von 12,30 m und 12,4 m verwendet würde, würden die letzteren Werte leider "12,3" und "12,40" anstelle von "12,30" und "12,4" ergeben.Zurück zur Sache: Es gibt mehr als eine sinnvolle Möglichkeit, nullbare Objekte auf Gleichheit zu vergleichen. C # vertritt den Standpunkt, dass sein
==
Operator das Verhalten von widerspiegeln sollteEquals
. VB.NET vertritt den Standpunkt, dass sein Verhalten das einiger anderer Sprachen widerspiegeln sollte, da jeder, der dasEquals
Verhalten wünscht, es verwenden könnteEquals
. In gewissem Sinne wäre die richtige Lösung, ein Drei-Wege-"Wenn" -Konstrukt zu haben und zu verlangen, dass der Code angeben muss, was in demnull
Fall geschehen soll, wenn der bedingte Ausdruck ein dreiwertiges Ergebnis zurückgibt . Da dies bei Sprachen, wie sie sind, keine Option ist, besteht die nächstbeste Alternative darin, einfach zu lernen, wie verschiedene Sprachen funktionieren, und zu erkennen, dass sie nicht gleich sind.Im Übrigen kann der in C fehlende Operator "Is" von Visual Basic verwendet werden, um zu testen, ob ein nullbares Objekt tatsächlich null ist. Während man sich vernünftigerweise fragen könnte, ob ein
if
Test a akzeptieren sollte, ist es eine nützliche FunktionBoolean?
, wenn die normalen Vergleichsoperatoren zurückkehren,Boolean?
anstattBoolean
wenn sie für nullfähige Typen aufgerufen werden. Übrigens, wenn man in VB.NET versucht, den Gleichheitsoperator anstelle von zu verwendenIs
, erhält man eine Warnung, dass das Ergebnis des Vergleichs immer sein wirdNothing
, und man sollte verwenden,Is
wenn man testen möchte, ob etwas null ist.quelle
== null
. Das Testen, ob ein nullbarer Werttyp einen Wert hat, erfolgt durch.hasValue
. Welchen Nutzen hat einIs Nothing
Bediener? C # hat zwaris
, testet aber die Typkompatibilität. In Anbetracht dessen bin ich mir wirklich nicht sicher, was Ihr letzter Absatz zu sagen versucht.null
, obwohl beide Sprachen dies als syntaktischen Zucker für eineHasValue
Überprüfung behandeln, zumindest in Fällen, in denen der Typ bekannt ist (ich bin nicht sicher) Welcher Code wird für Generika generiert?Kann sein , diesem Post gut helfen Ihnen:
Wenn ich mich richtig erinnere, bedeutet "Nichts" in VB "den Standardwert". Für einen Werttyp ist dies der Standardwert für einen Referenztyp, der null wäre. Daher ist es überhaupt kein Problem, einer Struktur nichts zuzuweisen.
quelle
<>
dreht sich alles um den Operator in VB und wie er mit nullbaren Typen arbeitet.Dies ist definitiv eine Verrücktheit von VB.
Wenn Sie in VB zwei nullfähige Typen vergleichen möchten, sollten Sie verwenden
Nullable.Equals()
.In Ihrem Beispiel sollte es sein:
quelle
Nullable<>.Equals()
. Man könnte erwarten, dass es genauso funktioniert (was C # tut).Nullable
war in den ersten Versionen von .NET nicht vorhanden. Sie wurde erstellt, nachdem C # und VB.NET einige Zeit nicht verfügbar waren und bereits ihr Null-Ausbreitungsverhalten bestimmt hatten. Erwarten Sie ehrlich, dass die Sprache mit einem Typ übereinstimmt, der seit mehreren Jahren nicht mehr erstellt wurde? Aus der Sicht eines VB.NET-Programmierers ist es Nullable.Equals, das nicht mit der Sprache übereinstimmt, sondern umgekehrt. (Da C # und VB beide dieselbeNullable
Definition verwenden, gab es keine Möglichkeit, dass sie mit beiden Sprachen übereinstimmen.)Ihr VB-Code ist einfach falsch - wenn Sie "x <> y" in "x = y" ändern, wird immer noch "false" als Ergebnis angezeigt. Die gebräuchlichste Ausdrucksweise für nullfähige Instanzen ist "Not x.Equals (y)". Dies führt zu demselben Verhalten wie "x! = Y" in C #.
quelle
x
sei dennnothing
, in diesem Fallx.Equals(y)
wird eine Ausnahme ausgelöst.