Ich bin heute darauf gestoßen und habe keine Ahnung, warum der C # -Compiler keinen Fehler auslöst.
Int32 x = 1;
if (x == null)
{
Console.WriteLine("What the?");
}
Ich bin verwirrt darüber, wie x jemals null sein könnte. Zumal diese Zuweisung definitiv einen Compilerfehler auslöst:
Int32 x = null;
Ist es möglich, dass x null wird, hat Microsoft nur beschlossen, diese Prüfung nicht in den Compiler zu stellen, oder wurde sie vollständig übersehen?
Update: Nachdem der Compiler mit dem Code zum Schreiben dieses Artikels herumgespielt hatte, kam plötzlich eine Warnung heraus, dass der Ausdruck niemals wahr sein würde. Jetzt bin ich wirklich verloren. Ich habe das Objekt in eine Klasse eingefügt und jetzt ist die Warnung verschwunden, aber es bleibt die Frage, ob ein Werttyp am Ende null sein kann.
public class Test
{
public DateTime ADate = DateTime.Now;
public Test ()
{
Test test = new Test();
if (test.ADate == null)
{
Console.WriteLine("What the?");
}
}
}
if (1 == 2)
. Es ist nicht die Aufgabe des Compilers, eine Codepfadanalyse durchzuführen. Dafür sind statische Analysewerkzeuge und Komponententests gedacht.int
generiert der Compiler nette Warnungen. Für die einfachen Typen wird der==
Operator durch die C # -Sprachenspezifikation definiert. Bei anderen (nicht einfachen) Strukturen vergisst der Compiler , eine Warnung auszugeben . Weitere Informationen finden Sie unter Falsche Compiler-Warnung beim Vergleich von struct mit null . Bei Strukturen, die keine einfachen Typen sind,==
muss der Operator von eineropeartor ==
Methode überladen werden , die Mitglied der Struktur ist (andernfalls ist no==
zulässig).Antworten:
Dies ist legal, da die Auflösung von Operatorüberlastungen einen einzigartigen besten Operator zur Auswahl hat. Es gibt einen == -Operator, der zwei nullbare Ints akzeptiert. Das int local kann in ein nullable int konvertiert werden. Das Null-Literal kann in ein null-int konvertiert werden. Daher ist dies eine legale Verwendung des Operators == und führt immer zu false.
In ähnlicher Weise können Sie auch "if (x == 12.6)" sagen, was ebenfalls immer falsch ist. Das int local ist in ein Double konvertierbar, das Literal ist in ein Double konvertierbar, und offensichtlich werden sie niemals gleich sein.
quelle
static bool operator == (SomeID a, String b)
und Markieren einesObsolete
? Wenn der zweite Operand ein untypisiertes Literalnull
ist, wäre dies eine bessere Übereinstimmung als jede Form, bei der angehobene Operatoren verwendet werden müssen. WennSomeID?
dies jedoch gleich istnull
, würde der angehobene Operator gewinnen.Es ist kein Fehler, da es eine (
int?
) Konvertierung gibt; Im angegebenen Beispiel wird eine Warnung generiert:Wenn Sie die IL überprüfen, werden Sie feststellen, dass der nicht erreichbare Zweig vollständig entfernt wird - er ist in einem Release-Build nicht vorhanden.
Beachten Sie jedoch, dass diese Warnung für benutzerdefinierte Strukturen mit Gleichheitsoperatoren nicht generiert wird. Früher in 2.0, aber nicht im 3.0-Compiler. Der Code wird immer noch entfernt (damit er weiß, dass der Code nicht erreichbar ist), es wird jedoch keine Warnung generiert:
Mit dem IL (für
Main
) - beachten Sie, dass alles außer demMyValue(1)
(was Nebenwirkungen haben könnte) entfernt wurde:das ist im Grunde:
quelle
Die Tatsache, dass ein Vergleich niemals wahr sein kann, bedeutet nicht, dass er illegal ist. Nein, ein Werttyp kann es jemals sein
null
.quelle
null
. Überlegen Sieint?
, für welchen syntaktischen Zucker es sich umNullable<Int32>
einen Werttyp handelt. Eine Variable vom Typint?
könnte sicherlich gleich seinnull
.==
Operators. Es ist jedoch wichtig zu beachten, dass die Instanz nicht wirklich null ist.Nein,
Int32 x
wird nie werdennull
."Warum ist ein Vergleich eines Werttyps mit null eine Warnung?" Artikel wird Ihnen helfen.
quelle
Ein Werttyp kann nicht sein
null
, obwohl er gleich sein kannnull
(berücksichtigenNullable<>
). In Ihrem Fall werden dieint
Variablen undnull
implizit umgewandeltNullable<Int32>
und verglichen.quelle
Ich vermute, dass Ihr bestimmter Test gerade vom Compiler optimiert wird, wenn er die IL generiert, da der Test niemals falsch sein wird.
Randnotiz: Ist es möglich, dass ein nullfähiger Int32 Int32 verwendet? x stattdessen.
quelle
Ich denke, das liegt daran, dass "==" ein Syntaxzucker ist, der tatsächlich einen Aufruf einer
System.Object.Equals
Methode darstellt, dieSystem.Object
Parameter akzeptiert . Null nach ECMA-Spezifikation ist ein spezieller Typ, von dem natürlich abgeleitet wirdSystem.Object
.Deshalb gibt es nur eine Warnung.
quelle
[BEARBEITET: Warnungen in Fehler umgewandelt und Operatoren explizit auf nullable anstatt auf den String-Hack aufmerksam gemacht.]
Gemäß dem cleveren Vorschlag von @ supercat in einem Kommentar oben können Sie mit den folgenden Operatorüberladungen einen Fehler beim Vergleich Ihres benutzerdefinierten Werttyps mit null generieren.
Durch die Implementierung von Operatoren, die mit nullbaren Versionen Ihres Typs verglichen werden, stimmt die Verwendung von null in einem Vergleich mit der nullbaren Version des Operators überein, sodass Sie den Fehler über das Attribut Obsolete generieren können.
Bis Microsoft uns unsere Compiler-Warnung zurückgibt, werde ich diese Problemumgehung durchführen, danke @supercat!
quelle
Foo a; Foo? b; ... if (a == b)...
, obwohl ein solcher Vergleich absolut legitim sein sollte. Der Grund, warum ich den "String Hack" vorgeschlagen habe, ist, dass er den obigen Vergleich erlauben würde, aber kreischen würdeif (a == null)
. Anstatt zu verwendenstring
, könnte man jeden anderen Referenztyp alsObject
oder ersetzenValueType
; Falls gewünscht, könnte man eine Dummy-Klasse mit einem privaten Konstruktor definieren, der niemals aufgerufen werden könnte, und sie berechtigenReferenceThatCanOnlyBeNull
.Ich denke, die beste Antwort, warum der Compiler dies akzeptiert, ist für generische Klassen. Betrachten Sie die folgende Klasse ...
Wenn der Compiler keine Vergleiche
null
für Werttypen akzeptiert , würde er diese Klasse im Wesentlichen unterbrechen, da eine implizite Einschränkung an ihren Typparameter angehängt wird (dh, er würde nur mit nicht wertbasierten Typen funktionieren).quelle
Mit dem Compiler können Sie jede Struktur, die das implementiert,
==
mit null vergleichen. Sie können sogar ein int mit null vergleichen (Sie würden jedoch eine Warnung erhalten).Wenn Sie den Code jedoch zerlegen, werden Sie feststellen, dass der Vergleich beim Kompilieren des Codes gelöst wird. So zum Beispiel dieser Code (wo
Foo
ist eine Struktur implementiert==
):Erzeugt diese IL:
Wie du siehst:
Übersetzt in:
Wohingegen:
Wird in false übersetzt:
quelle