it-swarm.com.de

Warum sagt uns "Objektreferenz nicht auf eine Instanz eines Objekts gesetzt" nicht, welches Objekt?

Wir starten ein System und erhalten manchmal die berühmte Ausnahme NullReferenceException mit der Meldung Object reference not set to an instance of an object.

Bei einer Methode mit fast 20 Objekten ist es jedoch überhaupt nicht sinnvoll, ein Protokoll zu haben, das besagt, dass ein Objekt null ist. Es ist, als würde man Ihnen als Sicherheitsagent eines Seminars sagen, dass ein Mann unter 100 Teilnehmern ein Terrorist ist. Das nützt dir überhaupt nichts. Sie sollten weitere Informationen erhalten, wenn Sie herausfinden möchten, welcher Mann der bedrohliche Mann ist.

Wenn wir den Fehler beseitigen möchten, müssen wir ebenfalls wissen, welches Objekt null ist.

Nun, seit einigen Monaten ist mir etwas in den Sinn gekommen, und das ist:

Warum gibt uns .NET nicht den Namen oder zumindest den Typ der Objektreferenz an, der null ist?. Kann es den Typ nicht aus Reflexion oder einer anderen Quelle verstehen?

Was sind die besten Methoden, um zu verstehen, welches Objekt null ist? Sollten wir die Nullfähigkeit von Objekten in diesen Kontexten immer manuell testen und das Ergebnis protokollieren? Gibt es einen besseren Weg?

pdate : Die Ausnahme The system cannot find the file specified hat die gleiche Natur. Sie können die Datei erst finden, wenn Sie sie an den Prozess anhängen und debuggen. Ich denke, diese Art von Ausnahmen kann intelligenter werden. Wäre es nicht besser, wenn .NET uns sagen könnte c:\temp.txt doesn't exist. anstelle dieser allgemeinen Nachricht? Als Entwickler stimme ich mit Ja.

39
Saeed Neamati

Das NullReferenceException sagt Ihnen im Grunde: Sie machen es falsch. Nicht mehr, nicht weniger. Im Gegenteil, es ist kein vollwertiges Debugging-Tool. In diesem Fall würde ich sagen, dass Sie es beide falsch machen, weil

  • es gibt eine NullReferenceException
  • sie haben es nicht so verhindert, dass Sie wissen, warum/wo es passiert ist
  • und vielleicht auch: Eine Methode, die 20 Objekte erfordert, scheint ein bisschen anders zu sein

Ich bin ein großer Fan davon, alles zu überprüfen, bevor etwas schief geht, und dem Entwickler gute Informationen zu liefern. Kurz gesagt: Schreiben Sie Schecks mit ArgumentNullException und den Likes und schreiben Sie den Namen selbst. Hier ist ein Beispiel:

void Method(string a, SomeObject b)
{
    if (a == null) throw ArgumentNullException("a");
    if (b == null) throw ArgumentNullException("b");

    // See how Nice this is, and what peace of mind this provides? As long as
    // nothing modifies a or b you can use them here and be 100% sure they're not
    // null. Should they be when entering the method, at least you know which one
    // is null.
    var c = FetchSomeObject();
    if(c == null)
    {
        throw InvalidOperationException("Fetching B failed!!");
    }

    // etc.
}

Sie können sich auch Code Contracts ansehen, es hat Macken, aber es funktioniert ziemlich gut und erspart Ihnen einige Eingaben.

28
stijn

Es sollte wirklich genau zeigen, was Sie anrufen möchten. Es ist, als würde man sagen: "Es gibt ein Problem. Sie müssen es beheben. Ich weiß, was es ist. Ich werde es Ihnen nicht sagen. Sie werden es herausfinden." Ein bisschen wie die Hälfte der Antworten auf diesen Stapelüberlauf, ironischerweise.

Wie nützlich wäre es zum Beispiel, wenn Sie dies hätten ...

Object reference (HttpContext.Current) not set to instance of an object

...? In den Code gehen zu müssen, ihn durchzugehen und herauszufinden, dass das, was Sie aufrufen möchten, null ist, ist in Ordnung, aber warum geben Sie uns nicht einfach eine kleine helfende Hand?

Ich bin damit einverstanden, dass es normalerweise nützlich ist, den Code durchzugehen, um zur Antwort zu gelangen (weil Sie wahrscheinlich mehr herausfinden werden), aber oft würde viel Zeit und Frust gespart, wenn das NullReferenceException text ähnelte eher dem obigen Beispiel.

Ich sag bloß.

19

Ihr Protokoll sollte eine Stapelverfolgung enthalten. Diese gibt Ihnen normalerweise einen Hinweis darauf, in welcher Zeile der Methode das Problem auftritt. Möglicherweise müssen Sie Ihren Release-Build mit PDB-Symbolen versehen, damit Sie eine Vorstellung davon haben, in welcher Zeile sich der Fehler befindet.

Zugegeben, es wird Ihnen in diesem Fall nicht helfen:

Foo.Bar.Baz.DoSomething()

Das Prinzip Tell Don't Ask kann helfen, solchen Code zu vermeiden.

Ich bin mir nicht sicher, warum die Informationen nicht enthalten sind - ich vermute, dass sie es zumindest in einem Debug-Build herausfinden könnten, wenn sie es wirklich wollten. Ein Crash-Dump und das Öffnen in WinDBG können hilfreich sein.

4
Paul Stovell

Ausnahmen wurden erstellt, um außergewöhnliche nicht tödliche Bedingungen in der Anrufkette zu signalisieren. Das heißt, sie sind nicht als Debugging-Tool konzipiert.

Wenn eine Nullzeigerausnahme ein Debugging-Tool wäre, würde sie die Programmausführung sofort abbrechen, sodass ein Debugger eine Verbindung herstellen und direkt auf die belastende Zeile zeigen könnte. Dies würde dem Programmierer all die verfügbaren Kontextinformationen geben. (Das ist ziemlich genau das, was ein Segfault aufgrund eines Nullzeigerzugriffs in C tut, wenn auch etwas grob.)

Die Nullzeigerausnahme ist jedoch als gültige Laufzeitbedingung konzipiert, die im normalen Programmablauf ausgelöst und abgefangen werden kann. Folglich müssen Leistungsüberlegungen berücksichtigt werden. Für jede Anpassung der Ausnahmemeldung müssen Zeichenfolgenobjekte zur Laufzeit erstellt, verkettet und zerstört werden. Daher ist eine statische Nachricht unbestreitbar schneller.

Ich sage nicht, dass die Laufzeit nicht so programmiert werden konnte, dass der Name der belastenden Referenz erhalten würde. Das könnte getan werden. Es würde Ausnahmen nur noch langsamer machen als sie sind. Wenn sich jemand genug darum kümmert, könnte eine solche Funktion sogar umschaltbar gemacht werden, so dass der Produktionscode nicht verlangsamt wird, sondern das Debuggen erleichtert wird. aber aus irgendeinem Grund scheint sich niemand genug darum gekümmert zu haben.

Cromulent hat den Nagel auf den Kopf getroffen, denke ich, aber es gibt auch den offensichtlichen Punkt, dass Sie nicht initialisierte Variablen haben, wenn Sie eine NullReferenceException erhalten. Das Argument, dass ca. 20 Objekte an eine Methode übergeben werden, kann nicht als Schadensbegrenzung angesehen werden: Als Ersteller eines Codeabschnitts müssen Sie für dessen Ausführung verantwortlich sein, einschließlich der Konformität mit dem Rest einer Codebasis sowie die ordnungsgemäße und korrekte Verwendung von Variablen usw.

es ist lästig, langweilig und manchmal langweilig, aber die Belohnungen am Ende sind es wert: In vielen Fällen musste ich Protokolldateien mit einem Gewicht von mehreren Gigabyte durchsuchen, und sie sind fast immer hilfreich. Bevor Sie jedoch zu dieser Phase gelangen, kann Ihnen der Debugger helfen, und vor dieser Phase erspart Ihnen eine gute Planung viel Schmerz (und ich meine auch keinen vollständig ausgearbeiteten Ansatz für Ihre Codelösung: einfache Skizzen und einige Notizen können und werden besser sein als nichts).

In Bezug auf die Object reference not set to an instance of an object Der Code kann keine Werte erraten, die uns gefallen könnten: Das ist unsere Aufgabe als Programmierer, und es bedeutet einfach, dass Sie eine nicht initialisierte Variable übergeben haben.

1
GMasucci

Wenn Sie mit der Antwort von @ stijn gehen und Null-Checks in Ihren Code einfügen möchten, sollte dieses Code-Snippet helfen. Hier einige Informationen zu Codefragmenten . Sobald Sie dies eingerichtet haben, geben Sie einfach argnull ein, drücken Sie zweimal die Tabulatortaste und füllen Sie dann die Lücke aus.

<CodeSnippet Format="1.0.0">
  <Header>
    <Title>EnsureArgNotNull</Title>
    <Shortcut>argnull</Shortcut>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>argument</ID>
        <ToolTip>The name of the argument that shouldn't be null</ToolTip>
        <Default>arg</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[if ($argument$ == null) throw new ArgumentNullException("$argument$");$end$]]>
    </Code>
  </Snippet>
</CodeSnippet>
0
user2023861

Erfahren Sie, wie Sie den Debugger verwenden. Genau dafür ist es konzipiert. Setzen Sie einen Haltepunkt für die betreffende Methode und los geht's.

Gehen Sie einfach Ihren Code durch und sehen Sie genau, welche Werte alle Ihre Variablen an bestimmten Punkten haben.

Edit: Ehrlich gesagt bin ich schockiert, dass noch niemand die Verwendung des Debuggers erwähnt hat.

0
Cromulent