Nachdem ich diese Frage auf HNQ gelesen hatte, las ich weiter über nullable Reference Types in C # 8 und machte einige Experimente.
Ich bin mir sehr bewusst, dass 9 von 10 oder noch öfter, wenn jemand sagt "Ich habe einen Compiler-Fehler gefunden!" Dies ist eigentlich beabsichtigt und ihr eigenes Missverständnis. Und da ich mich erst heute mit dieser Funktion befasst habe, habe ich offensichtlich kein sehr gutes Verständnis dafür. Schauen wir uns diesen Code an:
#nullable enable
class Program
{
static void Main()
{
var s = "";
var b = s == null; // If you comment this line out, the warning on the line below disappears
var i = s.Length; // warning CS8602: Dereference of a possibly null reference
}
}
Nachdem ich die Dokumentation gelesen habe, auf die ich oben verlinkt habe, würde ich erwarten, dass die s == null
Zeile eine Warnung s
ausgibt - schließlich ist sie eindeutig nicht nullwertfähig, sodass ein Vergleich mit null
nicht sinnvoll ist.
Stattdessen erhalte ich in der nächsten Zeile eine Warnung , und die Warnung besagt, dass s
dies eine Nullreferenz ist, obwohl es für einen Menschen offensichtlich ist, dass dies nicht der Fall ist.
Mehr über, wird die Warnung nicht , wenn wir vergleichen nicht angezeigt s
zu null
.
Ich habe ein bisschen gegoogelt und bin auf ein GitHub-Problem gestoßen , bei dem es sich um etwas ganz anderes handelte, aber dabei hatte ich ein Gespräch mit einem Mitwirkenden, der mehr Einblick in dieses Verhalten gab (z. B. "Nullprüfungen sind oft ein nützlicher Weg." den Compiler anzuweisen, seine vorherige Schlussfolgerung über die Nullfähigkeit einer Variablen zurückzusetzen. " ). Dies ließ mich jedoch mit der Hauptfrage unbeantwortet.
Anstatt ein neues GitHub-Problem zu erstellen und möglicherweise die Zeit der unglaublich beschäftigten Projektmitarbeiter in Anspruch zu nehmen, stelle ich dies der Community zur Verfügung.
Könnten Sie mir bitte erklären, was los ist und warum? Insbesondere , warum auf der keine Warnungen generiert s == null
Linie, und warum haben wir , CS8602
wenn es scheint nicht , wie eine null
Referenz hier möglich ist? Wenn die Inferenz der Nullbarkeit nicht kugelsicher ist, wie der verknüpfte GitHub-Thread andeutet, wie kann es dann schief gehen? Was wären einige Beispiele dafür?
quelle
?
das
nicht nullbar ist. Es wird nicht nullbar, einfach weil wir dumm genug waren, es damit zu vergleichennull
.Antworten:
Dies ist praktisch ein Duplikat der Antwort, die @stuartd verlinkt hat, daher werde ich hier nicht auf sehr tiefe Details eingehen. Die Wurzel der Sache ist jedoch, dass dies weder ein Sprachfehler noch ein Compilerfehler ist, sondern dass das beabsichtigte Verhalten genau so ist, wie es implementiert wurde. Wir verfolgen den Nullzustand einer Variablen. Wenn Sie die Variable zum ersten Mal deklarieren, lautet dieser Status NotNull, da Sie ihn explizit mit einem Wert initialisieren, der nicht null ist. Aber wir verfolgen nicht, woher dieser NotNull kam. Dies ist beispielsweise effektiv äquivalenter Code:
In beiden Fällen testen Sie explizit
s
aufnull
. Wir nehmen dies als Eingabe für die Flussanalyse, genau wie Mads in dieser Frage geantwortet hat: https://stackoverflow.com/a/59328672/2672518 . In dieser Antwort erhalten Sie bei der Rücksendung eine Warnung. In diesem Fall lautet die Antwort, dass Sie eine Warnung erhalten, dass Sie eine möglicherweise Nullreferenz dereferenziert haben.Ja, das tut es tatsächlich. Zum Compiler. Als Menschen können wir uns diesen Code ansehen und offensichtlich verstehen, dass er keine Nullreferenzausnahme auslösen kann. Die Art und Weise, wie die Analyse des nullbaren Flusses im Compiler implementiert wird, kann dies jedoch nicht. Wir haben einige Verbesserungen an dieser Analyse besprochen, bei denen wir zusätzliche Zustände hinzufügen, basierend darauf, woher der Wert stammt, aber wir haben entschieden, dass dies der Implementierung eine große Komplexität hinzufügt, um nicht viel Gewinn zu erzielen, da die einzigen Stellen, an denen Dies ist nützlich in solchen Fällen, in denen der Benutzer eine Variable mit einem
new
oder einem konstanten Wert initialisiert und sie dannnull
trotzdem überprüft .quelle
s == null
wird beispielsweise keine Warnung ausgegeben?#nullable enable
;string s = "";s = null;
kompiliert und funktioniert (es wird immer noch eine Warnung ausgegeben) Was sind die Vorteile der Implementierung, die es ermöglicht, einer "nicht nullbaren Referenz" im aktivierten Nullanmerkungskontext null zuzuweisen?s == null
. Möglicherweise befinden Sie sich beispielsweise in einer öffentlichen Methode und möchten eine Parameterüberprüfung durchführen. Oder vielleicht verwenden Sie eine Bibliothek, die falsch kommentiert wurde, und bis sie diesen Fehler behoben haben, müssen Sie sich mit null befassen, wo es nicht deklariert wurde. In beiden Fällen wäre es eine schlechte Erfahrung, wenn wir warnen würden. Zum Zulassen der Zuweisung: Lokale Variablenanmerkungen dienen nur zum Lesen. Sie beeinflussen die Laufzeit überhaupt nicht. Tatsächlich haben wir alle diese Warnungen in einem einzigen Fehlercode zusammengefasst, damit Sie sie deaktivieren können, wenn Sie die Code-Abwanderung reduzieren möchten.Ich habe die nullbaren Referenzen von C # 8 gerne übernommen, sobald sie verfügbar waren. Da ich die Notation [NotNull] (usw.) von ReSharper verwendet habe, habe ich einige Unterschiede zwischen den beiden festgestellt.
Der C # -Compiler kann getäuscht werden, aber er neigt dazu, vorsichtig zu sein (normalerweise nicht immer).
Als Referenz für zukünftige Besucher sind dies die Szenarien, in denen der Compiler ziemlich verwirrt war (ich gehe davon aus, dass alle diese Fälle beabsichtigt sind):
Es erlaubt jedoch, ein Konstrukt zu verwenden, um die Nullbarkeit zu überprüfen, wodurch auch die Warnung beseitigt wird:
oder (immer noch ziemlich coole) Attribute (finden Sie alle hier ):
string?
es sich nur um eine Zeichenfolge handelt,int?
eine wirdNullable<int>
und der Compiler gezwungen wird, sie auf wesentlich unterschiedliche Weise zu behandeln. Auch hier wählt der Compiler den sicheren Pfad und zwingt Sie, anzugeben, was Sie erwarten:Gelöste Einschränkungen geben:
Aber wenn wir keine Einschränkungen verwenden und das '?' Aus Daten können wir weiterhin Nullwerte mit dem Schlüsselwort 'default' einfügen:
Der letzte scheint mir schwieriger zu sein, da er das Schreiben von unsicherem Code ermöglicht.
Hoffe das hilft jemandem.
quelle
ThrowIfNull(s);
es mir versichert, dasss
es nicht null ist). In dem Artikel wird auch erklärt, wie nicht nullfähige Generika behandelt werden, während ich zeigte, wie Sie den Compiler "täuschen" können, indem Sie einen Nullwert haben, aber keine Warnung darüber.DoesNotReturnIf(bool)
.DoesNotReturnIfNull(nullable)
.