Gibt es in C # gute Gründe (außer einer besseren Fehlermeldung), jeder Funktion, bei der null kein gültiger Wert ist, Parameter-Null-Prüfungen hinzuzufügen? Offensichtlich löst der Code, der s verwendet, trotzdem eine Ausnahme aus. Und solche Überprüfungen machen die Code langsamer und schwieriger zu warten.
void f(SomeType s)
{
if (s == null)
{
throw new ArgumentNullException("s cannot be null.");
}
// Use s
}
Antworten:
Ja, es gibt gute Gründe:
NullReferenceException
Nun zu Ihren Einwänden:
Und für Ihre Behauptung:
"Ja wirklich?" Erwägen:
Das nutzt
s
, aber es löst keine Ausnahme aus. Wenn es ungültig ists
, null zu sein, und dies darauf hinweist, dass etwas nicht stimmt, ist eine Ausnahme hier das am besten geeignete Verhalten.Nun ist es eine andere Sache, wo Sie diese Überprüfungen der Argumentvalidierung platzieren. Sie können sich dafür entscheiden, dem gesamten Code in Ihrer eigenen Klasse zu vertrauen, ohne sich um private Methoden zu kümmern. Sie können sich dafür entscheiden, dem Rest Ihrer Baugruppe zu vertrauen, ohne sich um interne Methoden zu kümmern. Sie sollten mit ziemlicher Sicherheit die Argumente für öffentliche Methoden validieren.
Eine Randnotiz: Die Einzelparameter-Konstruktorüberladung von
ArgumentNullException
sollte nur der Parametername sein, daher sollte Ihr Test sein:Alternativ können Sie eine Erweiterungsmethode erstellen, die Folgendes zulässt:
In meiner Version der (generischen) Erweiterungsmethode wird der ursprüngliche Wert zurückgegeben, wenn er nicht null ist. So können Sie Folgendes schreiben:
Sie können auch eine Überladung haben, die den Parameternamen nicht annimmt, wenn Sie sich nicht zu sehr darum kümmern.
quelle
ThrowIfEmpty
amICollection
Debug.Assert
. Es ist noch wichtiger, Fehler in der Produktion (bevor sie echte Daten vermasseln) zu erkennen als in der Entwicklung.throw new ArgumentNullException(nameof(s))
Ich stimme Jon zu, aber ich würde noch eins hinzufügen.
Meine Einstellung, wann explizite Nullprüfungen hinzugefügt werden sollen, basiert auf folgenden Prämissen:
throw
Aussagen sind Aussagen .if
ist eine Aussage .throw
inif (x == null) throw whatever;
Wenn es keine Möglichkeit für die Anweisung ausgeführt werden , dann kann es nicht getestet werden und sollte ersetzt werden
Debug.Assert(x != null);
.Wenn es eine Möglichkeit gibt, diese Anweisung auszuführen, schreiben Sie die Anweisung und dann einen Komponententest, der sie ausführt.
Es ist besonders wichtig, dass öffentliche Methoden öffentlicher Typen ihre Argumente auf diese Weise überprüfen. Sie haben keine Ahnung, was Ihre Benutzer verrückt machen werden. Gib ihnen das "Hey du Bonehead, du machst es falsch!" Ausnahme so schnell wie möglich.
Private Methoden privater Typen sind dagegen viel wahrscheinlicher in der Situation, in der Sie die Argumente steuern, und können eine starke Garantie dafür haben, dass das Argument niemals null ist. Verwenden Sie eine Behauptung, um diese Invariante zu dokumentieren.
quelle
Ich benutze das jetzt seit einem Jahr:
Es ist ein Oneliner, und discard (
_
) bedeutet, dass keine unnötige Zuordnung erfolgt.quelle
Ohne eine explizite
if
Überprüfung kann es sehr schwierig sein, herauszufinden, was warnull
wenn Sie den Code nicht besitzen.Wenn Sie eine bekommen
NullReferenceException
aus der Tiefe einer Bibliothek ohne Quellcode erhalten, haben Sie wahrscheinlich große Probleme, herauszufinden, was Sie falsch gemacht haben.Diese
if
Überprüfungen machen Ihren Code nicht merklich langsamer.Beachten Sie, dass der Parameter für den
ArgumentNullException
Konstruktor ein Parametername und keine Nachricht ist.Ihr Code sollte sein
Ich habe ein Code-Snippet geschrieben, um dies zu vereinfachen:
quelle
Vielleicht möchten Sie einen Blick auf Codeverträge werfen, wenn Sie eine bessere Möglichkeit benötigen, um sicherzustellen, dass Sie keine Nullobjekte als Parameter erhalten.
quelle
Der Hauptvorteil besteht darin, dass Sie von Anfang an explizit mit den Anforderungen Ihrer Methode umgehen. Dies macht anderen Entwicklern, die an dem Code arbeiten, klar, dass es für einen Aufrufer wirklich ein Fehler ist, einen Nullwert an Ihre Methode zu senden.
Die Überprüfung stoppt auch die Ausführung der Methode, bevor ein anderer Code ausgeführt wird. Das heißt, Sie müssen sich keine Sorgen machen, dass Änderungen an der Methode vorgenommen werden, die noch nicht abgeschlossen sind.
quelle
Es erspart einige Fehlerbehebung, wenn Sie diese Ausnahme treffen.
Die ArgumentNullException gibt explizit an, dass "s" null war.
Wenn Sie diese Prüfung nicht haben und den Code blasen lassen, erhalten Sie eine NullReferenceException von einer nicht identifizierten Zeile in dieser Methode. In einem Release-Build erhalten Sie keine Zeilennummern!
quelle
Originalcode:
Schreiben Sie es um als:
[Bearbeiten] Der Grund für das Umschreiben mit
nameof
ist, dass es ein einfacheres Refactoring ermöglicht. Wenn sich der Name Ihrer Variablens
jemals ändert, werden auch die Debugging-Meldungen aktualisiert. Wenn Sie jedoch nur den Namen der Variablen fest codieren, ist diese möglicherweise veraltet, wenn im Laufe der Zeit Aktualisierungen vorgenommen werden. Dies ist eine gute Praxis in der Industrie.quelle
Also für Ihr Beispiel:
Oder:
Oder:
Oder ternär:
quelle