Sehr geehrte zukünftige Besucher, die Antworten auf diese Frage gelten auch für eine ArgumentNullException . Wenn Ihre Frage als Duplikat dieser Frage geschlossen wurde und bei Ihnen eine ANE auftritt, befolgen Sie bitte die Anweisungen in den Antworten, um das Problem zu debuggen und zu beheben.
@will ANE sollte nur auftreten, wenn eine Null als Parameter übergeben wird. Können Sie ein Beispiel geben, wenn eine ANE-Frage als Duplikat dieser Frage geschlossen wurde?
John Saunders
Es kam auf Meta, aber ich musste nach dem Link suchen. In Bezug auf diesen Kommentar ist eine ANE einfach eine NRE, aber jemand hat eine präventive Prüfung hinzugefügt, und Sie wissen zumindest genau, was null ist (der Argumentname wird angegeben), sodass die Diagnose etwas einfacher ist als eine direkte NRE.
Antworten:
2415
Was ist die Ursache?
Endeffekt
Sie versuchen, etwas zu verwenden, das null(oder Nothingin VB.NET) ist. Dies bedeutet, dass Sie es entweder auf nulloder gar nichts einstellen.
Wie alles andere wird nullherumgereicht. Wenn es nullin Verfahren „A“, könnte es diese Methode „B“ sein , eine übergeben nullzu Verfahren „A“.
null kann verschiedene Bedeutungen haben:
Objektvariablen, die nicht initialisiert sind und daher auf nichts verweisen. Wenn Sie in diesem Fall auf Eigenschaften oder Methoden solcher Objekte zugreifen, führt dies zu a NullReferenceException.
Der Entwickler verwendet nullabsichtlich, um anzuzeigen, dass kein aussagekräftiger Wert verfügbar ist. Beachten Sie, dass C # das Konzept nullbarer Datentypen für Variablen hat (wie Datenbanktabellen nullfähige Felder haben können) - Sie können nullihnen zuweisen , um anzuzeigen, dass kein Wert darin gespeichert ist, z. B. int? a = null;wenn das Fragezeichen angibt, dass null gespeichert werden darf variabel a. Sie können dies entweder mit if (a.HasValue) {...}oder mit überprüfen if (a==null) {...}. Nullable Variablen, wie in adiesem Beispiel, ermöglichen den a.Valueexpliziten Zugriff auf den Wert über oder wie gewohnt über a. Beachten Sie, dass es über den Zugriff a.Valuewirft einen InvalidOperationExceptionstatt eines , NullReferenceExceptionwenn aISnull- Sie sollten die Prüfung im Voraus durchführen. Wenn Sie also eine andere Variable mit Nullwert haben, int b;sollten Sie Zuweisungen wie if (a.HasValue) { b = a.Value; }oder kürzer ausführen if (a != null) { b = a; }.
Der Rest dieses Artikels geht detaillierter und zeigt Fehler, die viele Programmierer häufig machen und die zu a führen können NullReferenceException.
Genauer
Das runtimeWerfen eines bedeutet NullReferenceExceptionimmer dasselbe: Sie versuchen, eine Referenz zu verwenden, und die Referenz wird nicht initialisiert (oder sie wurde einmal initialisiert, wird aber nicht mehr initialisiert).
Dies bedeutet, dass die Referenz lautet nullund Sie nicht über eine nullReferenz auf Mitglieder (z. B. Methoden) zugreifen können . Der einfachste Fall:
string foo =null;
foo.ToUpper();
Dies wirft ein a NullReferenceExceptionin die zweite Zeile, da Sie die Instanzmethode ToUpper()für eine stringReferenz, auf die verweist, nicht aufrufen können null.
Debuggen
Wie finden Sie die Quelle von a NullReferenceException? Abgesehen von der Betrachtung der Ausnahme selbst, die genau an der Stelle ausgelöst wird, an der sie auftritt, gelten die allgemeinen Regeln für das Debuggen in Visual Studio: Platzieren Sie strategische Haltepunkte und überprüfen Sie Ihre Variablen , indem Sie entweder mit der Maus über deren Namen fahren und ein (öffnen) Schnell) Beobachten Sie das Fenster oder verwenden Sie die verschiedenen Debugging-Bereiche wie Locals und Autos.
Wenn Sie herausfinden möchten, wo die Referenz festgelegt ist oder nicht, klicken Sie mit der rechten Maustaste auf den Namen und wählen Sie "Alle Referenzen suchen". Sie können dann an jedem gefundenen Speicherort einen Haltepunkt platzieren und Ihr Programm mit dem angehängten Debugger ausführen. Jedes Mal, wenn der Debugger an einem solchen Haltepunkt unterbrochen wird, müssen Sie feststellen, ob die Referenz nicht null sein soll, die Variable überprüfen und sicherstellen, dass sie auf eine Instanz verweist, wenn Sie dies erwarten.
Wenn Sie dem Programmablauf auf diese Weise folgen, können Sie den Speicherort ermitteln, an dem die Instanz nicht null sein sollte und warum sie nicht richtig festgelegt ist.
Beispiele
Einige häufige Szenarien, in denen die Ausnahme ausgelöst werden kann:
Generisch
ref1.ref2.ref3.member
Wenn ref1 oder ref2 oder ref3 null ist, erhalten Sie eine NullReferenceException. Wenn Sie das Problem lösen möchten, finden Sie heraus, welches Null ist, indem Sie den Ausdruck in sein einfacheres Äquivalent umschreiben:
Insbesondere in HttpContext.Current.User.Identity.Nameder HttpContext.Currentkönnte null sein, oder die UserEigenschaft null sein könnte, oder die IdentityEigenschaft null sein könnte.
Indirekt
publicclassPerson{publicintAge{get;set;}}publicclassBook{publicPersonAuthor{get;set;}}publicclassExample{publicvoidFoo(){Book b1 =newBook();int authorAge = b1.Author.Age;// You never initialized the Author property.// there is no Person to get an Age from.}}
Wenn Sie die untergeordnete Nullreferenz (Person) vermeiden möchten, können Sie sie im Konstruktor des übergeordneten (Buch-) Objekts initialisieren.
Initialisierer für verschachtelte Objekte
Gleiches gilt für verschachtelte Objektinitialisierer:
Book b1 =newBook{Author={Age=45}};
Dies bedeutet
Book b1 =newBook();
b1.Author.Age=45;
Während das newSchlüsselwort verwendet wird, wird nur eine neue Instanz von erstellt Book, jedoch keine neue Instanz von Person, sodass Authordie Eigenschaft weiterhin vorhanden ist null.
Die verschachtelte Auflistung Initializersverhält sich wie folgt:
Person p1 =newPerson{Books={newBook{Title="Title1"},newBook{Title="Title2"},}};
Dies bedeutet
Person p1 =newPerson();
p1.Books.Add(newBook{Title="Title1"});
p1.Books.Add(newBook{Title="Title2"});
Das new Personerstellt nur eine Instanz von Person, aber die BooksSammlung ist noch null. Die Auflistungssyntax erstellt Initializerkeine Auflistung für p1.Books, sondern übersetzt nur in die p1.Books.Add(...)Anweisungen.
Array
int[] numbers =null;int n = numbers[0];// numbers is null. There is no array to index.
Array-Elemente
Person[] people =newPerson[5];
people[0].Age=20// people[0] is null. The array was allocated but not// initialized. There is no Person to set the Age for.
Gezackte Arrays
long[][] array =newlong[1][];
array[0][0]=3;// is null because only the first dimension is yet initialized.// Use array[0] = new long[2]; first.
Sammlung / Liste / Wörterbuch
Dictionary<string,int> agesForNames =null;int age = agesForNames["Bob"];// agesForNames is null.// There is no Dictionary to perform the lookup.
Bereichsvariable (indirekt / verzögert)
publicclassPerson{publicstringName{get;set;}}var people =newList<Person>();
people.Add(null);var names =from p in people select p.Name;string firstName = names.First();// Exception is thrown here, but actually occurs// on the line above. "p" is null because the// first element we added to the list is null.
Veranstaltungen
publicclassDemo{publiceventEventHandlerStateChanged;protectedvirtualvoidOnStateChanged(EventArgs e){StateChanged(this, e);// Exception is thrown here // if no event handlers have been attached// to StateChanged event}}###Bad Naming Conventions:If you named fields differently from locals, you might have realized that you never initialized the field.
Dies kann gelöst werden, indem Sie der Konvention folgen, um Feldern einen Unterstrich voranzustellen:
privateCustomer _customer;
ASP.NET-Seitenlebenszyklus:
publicpartialclassIssues_Edit:System.Web.UI.Page{protectedTestIssue myIssue;protectedvoidPage_Load(object sender,EventArgs e){if(!IsPostBack){// Only called on first load, not when button clicked
myIssue =newTestIssue();}}protectedvoidSaveButton_Click(object sender,EventArgs e){
myIssue.Entry="NullReferenceException here!";}}
ASP.NET-Sitzungswerte
// if the "FirstName" session value has not yet been set,// then this line will throw a NullReferenceExceptionstring firstName =Session["FirstName"].ToString();
Leere Ansichtsmodelle für ASP.NET MVC
Wenn die Ausnahme auftritt, wenn auf eine Eigenschaft von @Modelin verwiesen wird ASP.NET MVC View, müssen Sie verstehen, dass die Modelin Ihrer Aktionsmethode festgelegt wird, wenn Sie returneine Ansicht erstellen. Wenn Sie ein leeres Modell (oder eine Modelleigenschaft) von Ihrem Controller zurückgeben, tritt die Ausnahme auf, wenn die Ansichten darauf zugreifen:
// ControllerpublicclassRestaurant:Controller{publicActionResultSearch(){returnView();// Forgot the provide a Model here.}}// Razor view @foreach(var restaurantSearch inModel.RestaurantSearch)// Throws.{}<p>@Model.somePropertyName</p><!--Alsothrows-->
Erstellungsreihenfolge und Ereignisse der WPF-Steuerung
WPFSteuerelemente werden während des Aufrufs InitializeComponentin der Reihenfolge erstellt, in der sie im visuellen Baum angezeigt werden. Bei NullReferenceExceptionfrüh erstellten Steuerelementen mit Ereignishandlern usw. wird ein Wert ausgelöst, bei InitializeComponentdem spät erstellte Steuerelemente referenziert werden.
Beispielsweise :
<Grid><!-- Combobox declared first --><ComboBoxName="comboBox1"Margin="10"SelectedIndex="0"SelectionChanged="comboBox1_SelectionChanged"><ComboBoxItemContent="Item 1"/><ComboBoxItemContent="Item 2"/><ComboBoxItemContent="Item 3"/></ComboBox><!-- Label declared later --><LabelName="label1"Content="Label"Margin="10"/></Grid>
Hier comboBox1wird vorher erstellt label1. Wenn comboBox1_SelectionChangedversucht wird, auf `label1 zu verweisen, wurde es noch nicht erstellt.
Eine Änderung der Reihenfolge der Deklarationen in der XAML(dh Auflistung label1vor comboBox1, Ignorieren von Fragen der Designphilosophie, würde zumindest das NullReferenceExceptionhier lösen .
Besetzung mit as
var myThing = someObject asThing;
Dies wirft kein, InvalidCastExceptionsondern gibt ein zurück, nullwenn die Umwandlung fehlschlägt (und wenn someObjectes selbst null ist). Also sei dir dessen bewusst.
LINQ FirstOrDefault()undSingleOrDefault()
Die einfachen Versionen First()und Single()werfen Ausnahmen, wenn es nichts gibt. Die "OrDefault" -Versionen geben in diesem Fall null zurück. Also sei dir dessen bewusst.
für jedes
foreachwird ausgelöst, wenn Sie versuchen, die Nullsammlung zu iterieren. Wird normalerweise durch unerwartete nullErgebnisse von Methoden verursacht, die Sammlungen zurückgeben.
List<int> list =null;foreach(var v in list){}// exception
Realistischeres Beispiel - Wählen Sie Knoten aus dem XML-Dokument aus. Wird ausgelöst, wenn keine Knoten gefunden werden, aber das anfängliche Debuggen zeigt, dass alle Eigenschaften gültig sind:
foreach(var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
Möglichkeiten zu vermeiden
Überprüfen nullund ignorieren Sie explizit Nullwerte.
Wenn Sie erwarten, dass die Referenz manchmal null ist, können Sie dies überprüfen, nullbevor Sie auf Instanzmitglieder zugreifen:
Suchen Sie explizit nach nulleinem Standardwert und geben Sie ihn an.
Methodenaufruf, von dem Sie erwarten, dass er eine Instanz zurückgibt null, kann zurückgegeben werden , beispielsweise wenn das gesuchte Objekt nicht gefunden werden kann. In diesem Fall können Sie einen Standardwert zurückgeben:
Suchen Sie explizit nach nullMethodenaufrufen und lösen Sie eine benutzerdefinierte Ausnahme aus.
Sie können auch eine benutzerdefinierte Ausnahme auslösen, um sie im aufrufenden Code abzufangen:
stringGetCategory(string bookTitle){var book = library.FindBook(bookTitle);// This may return nullif(book ==null)thrownewBookNotFoundException(bookTitle);// Your custom exceptionreturn book.Category;}
Verwenden Sie Debug.Assertdiese Option, wenn ein Wert niemals sein sollte null, um das Problem früher zu erkennen, als die Ausnahme auftritt.
Wenn Sie während der Entwicklung wissen, dass eine Methode möglicherweise zurückkehren kann, aber niemals zurückkehren sollte null, können Sie sie verwenden Debug.Assert(), um so schnell wie möglich zu brechen, wenn sie auftritt:
stringGetTitle(int knownBookID){// You know this should never return null.var book = library.GetBook(knownBookID);// Exception will occur on the next line instead of at the end of this method.Debug.Assert(book !=null,"Library didn't return a book for known book ID.");// Some other codereturn book.Title;// Will never throw NullReferenceException in Debug mode.}
Verwenden Sie diese Option GetValueOrDefault()für nullableWerttypen, um einen Standardwert anzugeben, wenn dies der Fall ist null.
DateTime? appointment =null;Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));// Will display the default value provided (DateTime.Now), because appointment is null.
appointment =newDateTime(2022,10,20);Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));// Will display the appointment date, not the default
Verwenden Sie den Null-Koaleszenz-Operator: ??[C #] oder If()[VB].
Die Abkürzung zum Bereitstellen eines Standardwerts, wenn a nullauftritt:
IServiceCreateService(ILogger log,Int32? frobPowerLevel){var serviceImpl =newMyService(log ??NullLog.Instance);// Note that the above "GetValueOrDefault()" can also be rewritten to use// the coalesce operator:
serviceImpl.FrobPowerLevel= frobPowerLevel ??5;}
Verwenden Sie den Nullbedingungsoperator: ?.oder ?[x]für Arrays (verfügbar in C # 6 und VB.NET 14):
Dies wird manchmal auch als sicherer Navigations- oder Elvis-Operator (nach seiner Form) bezeichnet. Wenn der Ausdruck auf der linken Seite des Operators null ist, wird die rechte Seite nicht ausgewertet und stattdessen null zurückgegeben. Das bedeutet Fälle wie diesen:
var title = person.Title.ToUpper();
Wenn die Person keinen Titel hat, wird eine Ausnahme ausgelöst, da versucht wird, ToUppereine Eigenschaft mit einem Nullwert aufzurufen .
In C# 5und unten kann dies bewacht werden mit:
var title = person.Title==null?null: person.Title.ToUpper();
Jetzt ist die Titelvariable null, anstatt eine Ausnahme auszulösen. C # 6 führt hierfür eine kürzere Syntax ein:
var title = person.Title?.ToUpper();
Dies führt dazu, dass die Titelvariable vorhanden ist nullund der Aufruf von ToUppernicht erfolgt, wenn dies der Fall person.Titleist null.
Natürlich müssen Sie immer noch nach titlenull suchen oder den Nullbedingungsoperator zusammen mit dem Null-Koaleszenzoperator ( ??) verwenden, um einen Standardwert anzugeben:
// regular null checkint titleLength =0;if(title !=null)
titleLength = title.Length;// If title is null, this would throw NullReferenceException// combining the `?` and the `??` operatorint titleLength = title?.Length??0;
Ebenso können Sie für Arrays ?[i]Folgendes verwenden:
Dies führt Folgendes aus: Wenn myIntArraynull ist, gibt der Ausdruck null zurück und Sie können ihn sicher überprüfen. Wenn es ein Array enthält, funktioniert es wie folgt:
elem = myIntArray[i];und gibt das i<sup>th</sup>Element zurück.
Verwenden Sie den Nullkontext (verfügbar in C # 8):
Die dort eingeführten C# 8Nullkontexte und nullbaren Referenztypen führen eine statische Analyse von Variablen durch und geben eine Compilerwarnung aus, wenn ein Wert möglicherweise null sein kann oder auf null gesetzt wurde. Mit den nullbaren Referenztypen können Typen explizit null sein.
Der annullierbare Annotationskontext und der nullbare Warnkontext können für ein Projekt mithilfe des NullableElements in Ihrer csprojDatei festgelegt werden. Dieses Element konfiguriert, wie der Compiler die Nullfähigkeit von Typen interpretiert und welche Warnungen generiert werden. Gültige Einstellungen sind:
enable: Der annullierbare Annotationskontext ist aktiviert. Der nullbare Warnkontext ist aktiviert. Variablen eines Referenztyps, z. B. eine Zeichenfolge, können nicht auf Null gesetzt werden. Alle Nullbarkeitswarnungen sind aktiviert.
disable: Der annullierbare Annotationskontext ist deaktiviert. Der nullbare Warnkontext ist deaktiviert. Variablen eines Referenztyps werden ebenso wie frühere Versionen von C # nicht berücksichtigt. Alle Nullfähigkeitswarnungen sind deaktiviert.
Nur sicher: Der nullfähige Annotationskontext ist aktiviert. Der nullbare Warnkontext ist nur sicher. Variablen eines Referenztyps können nicht gelöscht werden. Alle Sicherheitswarnungen zur Nichtigkeitsfähigkeit sind aktiviert.
Warnungen: Der annullierbare Annotationskontext ist deaktiviert. Der nullbare Warnkontext ist aktiviert. Variablen eines Referenztyps sind nicht bekannt. Alle Nullbarkeitswarnungen sind aktiviert.
safeonlywarnings: Der annullierbare Annotationskontext ist deaktiviert. Der nullbare Warnkontext ist nur sicher. Variablen eines Referenztyps sind nicht bekannt. Alle Sicherheitswarnungen zur Nichtigkeitsfähigkeit sind aktiviert.
Ein nullbarer Referenztyp wird mit derselben Syntax wie nullbare Werttypen notiert: a ?wird an den Typ der Variablen angehängt.
Spezielle Techniken zum Debuggen und Beheben von Null-Derefs in Iteratoren
C#unterstützt "Iteratorblöcke" (in einigen anderen gängigen Sprachen "Generatoren" genannt). Null-Dereferenzierungsausnahmen können aufgrund der verzögerten Ausführung in Iteratorblöcken besonders schwierig zu debuggen sein:
publicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){for(int i =0; i < count;++i)yieldreturn f.MakeFrob();}...FrobFactory factory = whatever;IEnumerable<Frobs> frobs =GetFrobs();...foreach(Frob frob in frobs){...}
Wenn whateverErgebnisse in nulldann MakeFrobwird werfen. Nun könnte man denken, dass das Richtige das Folgende ist:
// DON'T DO THISpublicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){if(f ==null)thrownewArgumentNullException("f","factory must not be null");for(int i =0; i < count;++i)yieldreturn f.MakeFrob();}
Warum ist das falsch? Da der Iteratorblock eigentlich nicht laufen , bis die foreach! Der Aufruf, GetFrobseinfach ein Objekt zurückzugeben, das bei Iteration den Iteratorblock ausführt.
Wenn Sie eine Nullprüfung wie diese schreiben, verhindern Sie die Null-Dereferenzierung, aber Sie verschieben die Nullargument-Ausnahme an den Punkt der Iteration , nicht an den Punkt des Aufrufs , und das Debuggen ist sehr verwirrend .
Die richtige Lösung ist:
// DO THISpublicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){// No yields in a public method that throws!if(f ==null)thrownewArgumentNullException("f","factory must not be null");returnGetFrobsForReal(f, count);}privateIEnumerable<Frob>GetFrobsForReal(FrobFactory f,int count){// Yields in a private methodDebug.Assert(f !=null);for(int i =0; i < count;++i)yieldreturn f.MakeFrob();}
Erstellen Sie also eine private Hilfsmethode mit der Iteratorblocklogik und eine öffentliche Oberflächenmethode, die die Nullprüfung durchführt und den Iterator zurückgibt. Wenn jetzt GetFrobsaufgerufen wird, erfolgt die Nullprüfung sofort und wird dann GetFrobsForRealausgeführt, wenn die Sequenz wiederholt wird.
Wenn Sie die Referenzquelle für LINQObjekte untersuchen, werden Sie feststellen, dass diese Technik durchgehend verwendet wird. Das Schreiben ist etwas umständlicher, erleichtert jedoch das Debuggen von Nullitätsfehlern erheblich. Optimieren Sie Ihren Code für die Bequemlichkeit des Anrufers und nicht für die Bequemlichkeit des Autors .
Ein Hinweis zu Null-Dereferenzen in unsicherem Code
C#hat einen "unsicheren" Modus, der, wie der Name schon sagt, äußerst gefährlich ist, da die normalen Sicherheitsmechanismen, die Speichersicherheit und Typensicherheit bieten, nicht durchgesetzt werden. Sie sollten keinen unsicheren Code schreiben, es sei denn, Sie haben ein gründliches und tiefes Verständnis der Funktionsweise des Speichers .
Im unsicheren Modus sollten Sie zwei wichtige Fakten kennen:
einen Null dereferenzieren Zeiger erzeugt die gleiche Ausnahme als Null Dereferenzieren Referenz
Das Dereferenzieren eines ungültigen Nicht-Null-Zeigers kann unter bestimmten Umständen zu dieser Ausnahme führen
Um zu verstehen, warum das so ist, ist es hilfreich zu verstehen, wie .NET überhaupt Null-Dereferenzierungsausnahmen erzeugt. (Diese Angaben gelten für .NET unter Windows. Andere Betriebssysteme verwenden ähnliche Mechanismen.)
Speicher wird in virtualisiert Windows; Jeder Prozess erhält einen virtuellen Speicherplatz mit vielen "Seiten" Speicher, die vom Betriebssystem verfolgt werden. Auf jeder Speicherseite sind Flags gesetzt, die bestimmen, wie sie verwendet werden dürfen: Lesen, Schreiben, Ausführen usw. Die unterste Seite ist als "Fehler erzeugen, wenn sie jemals in irgendeiner Weise verwendet wurde" markiert.
Sowohl ein Nullzeiger als auch eine Nullreferenz in C#werden intern als die Zahl Null dargestellt. Daher führt jeder Versuch, sie in den entsprechenden Speicher zu dereferenzieren, dazu, dass das Betriebssystem einen Fehler erzeugt. Die .NET-Laufzeit erkennt diesen Fehler und verwandelt ihn in die Null-Dereferenzierungsausnahme.
Aus diesem Grund führt die Dereferenzierung sowohl eines Nullzeigers als auch einer Nullreferenz zu derselben Ausnahme.
Was ist mit dem zweiten Punkt? Das Dereferenzieren eines ungültigen Zeigers, der auf die unterste Seite des virtuellen Speichers fällt, verursacht denselben Betriebssystemfehler und damit dieselbe Ausnahme.
Warum macht das Sinn? Angenommen, wir haben eine Struktur mit zwei Ints und einen nicht verwalteten Zeiger gleich null. Wenn wir versuchen, das zweite int in der Struktur zu dereferenzieren, CLRwird nicht versucht, auf den Speicher an Position Null zuzugreifen. Es wird auf den Speicher an Position vier zugreifen. Aber logischerweise ist dies eine Null-Dereferenzierung, da wir über die Null zu dieser Adresse gelangen .
Wenn Sie mit unsicherem Code arbeiten und eine Null-Dereferenzierungsausnahme erhalten, beachten Sie nur, dass der fehlerhafte Zeiger nicht null sein muss. Es kann sich um eine beliebige Stelle auf der untersten Seite handeln, und diese Ausnahme wird erzeugt.
Vielleicht ist dies ein dummer Kommentar, aber wäre der erste und beste Weg, um dieses Problem zu vermeiden, die Initialisierung des Objekts? Wenn dieser Fehler auftritt, liegt dies normalerweise daran, dass ich vergessen habe, so etwas wie das Array-Element zu initialisieren. Ich denke, es ist weitaus seltener, das Objekt als null zu definieren und dann darauf zu verweisen. Vielleicht geben Sie den Weg, um jedes Problem neben der Beschreibung zu lösen. Immer noch ein guter Beitrag.
JPK
30
Was ist, wenn kein Objekt vorhanden ist, sondern der Rückgabewert einer Methode oder Eigenschaft?
John Saunders
6
Das Buch- / Autorenbeispiel ist etwas seltsam ... Wie kompiliert sich das überhaupt? Wie funktioniert Intellisense überhaupt? Was ist das? Ich bin nicht gut mit Computern ...
5
@ Will: Hilft meine letzte Bearbeitung? Wenn nicht, geben Sie bitte genauer an, was Sie als Problem ansehen.
John Saunders
6
@ JohnSaunders Oh, nein, sorry, ich meinte die Objektinitialisierungsversion davon. new Book { Author = { Age = 45 } };Wie funktioniert die innere Initialisierung überhaupt ... Ich kann mir keine Situation vorstellen, in der die innere Initialisierung jemals funktionieren würde, aber sie kompiliert und Intellisense funktioniert ... Es sei denn für Strukturen?
311
NullReference-Ausnahme - Visual Basic
Das NullReference Exceptionfür Visual Basic unterscheidet sich nicht von dem in C # . Schließlich melden beide dieselbe Ausnahme, die in .NET Framework definiert ist, das sie beide verwenden. Ursachen, die nur für Visual Basic gelten, sind selten (möglicherweise nur eine).
Diese Antwort verwendet Visual Basic-Begriffe, -Syntax und -Kontext. Die verwendeten Beispiele stammen aus einer großen Anzahl früherer Fragen zum Stapelüberlauf. Dies ist Relevanz zu maximieren , indem die Verwendung von Arten von Situationen oft in Beiträgen gesehen. Ein bisschen mehr Erklärung wird auch für diejenigen gegeben, die es brauchen könnten. Ein ähnliches Beispiel wie Ihr ist hier sehr wahrscheinlich aufgeführt.
Hinweis:
Dies ist konzeptbasiert: Es gibt keinen Code, den Sie in Ihr Projekt einfügen können. Es soll Ihnen helfen zu verstehen, was ein NullReferenceException(NRE) verursacht, wie man es findet, wie man es behebt und wie man es vermeidet. Ein NRE kann auf viele Arten verursacht werden, daher ist es unwahrscheinlich, dass dies Ihre einzige Begegnung ist.
Die Beispiele (aus Stack Overflow-Posts) zeigen nicht immer, wie man überhaupt etwas am besten macht.
Typischerweise wird das einfachste Mittel verwendet.
Grundlegende Bedeutung
Die Meldung "Objekt nicht auf eine Instanz von Objekt festgelegt" bedeutet, dass Sie versuchen, ein Objekt zu verwenden, das nicht initialisiert wurde. Dies läuft auf eines davon hinaus:
Ihr Code hat eine Objektvariable deklariert , diese jedoch nicht initialisiert (Instanz erstellen oder instanziieren ).
Etwas, von dem Ihr Code angenommen hat, dass es ein Objekt initialisiert, hat dies nicht getan
Möglicherweise hat ein anderer Code ein noch verwendetes Objekt vorzeitig ungültig gemacht
Die Ursache finden
Da das Problem eine Objektreferenz ist Nothing, besteht die Antwort darin, sie zu untersuchen, um herauszufinden, welche. Stellen Sie dann fest, warum es nicht initialisiert wurde. Halten Sie die Maus über die verschiedenen Variablen und Visual Studio (VS) zeigt ihre Werte an - der Schuldige ist Nothing.
Sie sollten auch alle Try / Catch-Blöcke aus dem entsprechenden Code entfernen, insbesondere solche, bei denen der Catch-Block nichts enthält. Dies führt dazu, dass Ihr Code abstürzt, wenn er versucht, ein Objekt zu verwenden Nothing. Dies ist das, was Sie möchten, da es den genauen Ort des Problems identifiziert und es Ihnen ermöglicht, das Objekt zu identifizieren, das es verursacht.
Ein MsgBoxangezeigter Catch Error while...hilft wenig. Diese Methode führt auch zu sehr schlechten Fragen zum Stapelüberlauf, da Sie die tatsächliche Ausnahme, das betroffene Objekt oder sogar die Codezeile, in der sie auftritt, nicht beschreiben können.
Sie können Ihre Objekte auch mit Locals Window( Debug -> Windows -> Locals ) untersuchen.
Sobald Sie wissen, was und wo das Problem liegt, ist es normalerweise recht einfach zu beheben und schneller als das Posten einer neuen Frage.
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Das Problem ist, dass Dimkein CashRegister- Objekt erstellt wird . Es wird nur eine Variable mit diesem Namen deklariert reg. Das Deklarieren einer Objektvariablen und das Erstellen einer Instanz sind zwei verschiedene Dinge.
Abhilfe
Der NewOperator kann häufig verwendet werden, um die Instanz zu erstellen, wenn Sie sie deklarieren:
Dim reg AsNew CashRegister ' [New] creates instance, invokes the constructor' Longer, more explicit form:Dim reg As CashRegister =New CashRegister
Wenn es nur angebracht ist, die Instanz später zu erstellen:
Hinweis: Sie nicht verwenden , Dimwieder in einem Verfahren, einschließlich dem Konstruktor ( Sub New):
Private reg As CashRegister
'...PublicSubNew()'...Dim reg AsNew CashRegister
EndSub
Dadurch wird eine lokale Variable erstellt, regdie nur in diesem Kontext (Sub) vorhanden ist. Die regVariable mit Modulebene, Scopedie Sie überall sonst verwenden, bleibt erhalten Nothing.
Das Fehlen des NewOperators ist die häufigste Ursache fürNullReference Exceptions die in den Stapelüberlauffragen behandelten Fragen.
Visual Basic versucht, den Prozess wiederholt zu verdeutlichen, indem es Folgendes verwendet New: Mit dem NewOperator wird ein neues Objekt erstellt und Sub Newder Konstruktor aufgerufen, in dem Ihr Objekt eine andere Initialisierung durchführen kann.
Um klar zu sein, deklariertDim (oder Private) nur eine Variable und ihre . Der Umfang der Variablen - ob sie für das gesamte Modul / die gesamte Klasse vorhanden ist oder für eine Prozedur lokal ist - wird dadurch bestimmt, wo sie deklariert wird. Definiert die Zugriffsebene, nicht den Bereich .TypePrivate | Friend | Public
Dieses Array wurde nur deklariert, nicht erstellt. Es gibt verschiedene Möglichkeiten, ein Array zu initialisieren:
Private arr asString()=NewString(10){}' orPrivate arr()AsString=NewString(10){}' For a local array (in a procedure) and using 'Option Infer':Dim arr =NewString(10){}
Hinweis: Ab VS 2010 sind beim Initialisieren eines lokalen Arrays mit einem Literal und Option Inferdie Elemente As <Type>und Newoptional:
Dim myDbl AsDouble()={1.5,2,9.9,18,3.14}Dim myDbl =NewDouble(){1.5,2,9.9,18,3.14}Dim myDbl()={1.5,2,9.9,18,3.14}
Der Datentyp und die Arraygröße werden aus den zugewiesenen Daten abgeleitet. Klasse / Modulebene Erklärungen erfordern nach wie vor As <Type>mit Option Strict:
Private myDoubles AsDouble()={1.5,2,9.9,18,3.14}
Beispiel: Array von Klassenobjekten
Dim arrFoo(5)As Foo
For i AsInteger=0To arrFoo.Count -1
arrFoo(i).Bar = i *10' ExceptionNext
Das Array wurde erstellt, die darin enthaltenen FooObjekte jedoch nicht.
Abhilfe
For i AsInteger=0To arrFoo.Count -1
arrFoo(i)=New Foo()' Create Foo instance
arrFoo(i).Bar = i *10Next
Die Verwendung eines List(Of T)Testaments macht es ziemlich schwierig, ein Element ohne ein gültiges Objekt zu haben:
Dim FooList AsNew List(Of Foo)' List created, but it is emptyDim f As Foo ' Temporary variable for the loopFor i AsInteger=0To5
f =New Foo()' Foo instance created
f.Bar = i *10
FooList.Add(f)' Foo object added to listNext
.NET-Sammlungen (von denen es viele Varianten gibt - Listen, Wörterbuch usw.) müssen ebenfalls instanziiert oder erstellt werden.
Private myList As List(Of String)..
myList.Add("ziggy")' NullReference
Sie erhalten dieselbe Ausnahme aus demselben Grund - myListwurde nur deklariert, aber keine Instanz erstellt. Das Mittel ist das gleiche:
myList =New List(Of String)' Or create an instance when declared:Private myList AsNew List(Of String)
Ein häufiges Versehen ist eine Klasse, die eine Sammlung verwendet Type:
PublicClass Foo
Private barList As List(Of Bar)FriendFunction BarCount AsIntegerReturn barList.Count
EndFunctionFriendSub AddItem(newBar As Bar)If barList.Contains(newBar)=FalseThen
barList.Add(newBar)EndIfEndFunction
Jede Prozedur führt zu einer NRE, da sie barListnur deklariert und nicht instanziiert wird. Durch das Erstellen einer Instanz von Foowird nicht auch eine Instanz des internen erstellt barList. Möglicherweise war dies die Absicht, dies im Konstruktor zu tun:
PublicSubNew' Constructor' Stuff to do when a new Foo is created...
barList =New List(Of Bar)EndSub
Dies ist nach wie vor falsch:
PublicSubNew()' Creates another barList local to this procedureDim barList AsNew List(Of Bar)EndSub
Arbeiten mit Datenbanken bieten viele Möglichkeiten für einen Nullreference , weil es viele Objekte (sein Command, Connection, Transaction, Dataset, DataTable, DataRowsauf einmal ....) im Einsatz. Hinweis: Es spielt keine Rolle, welchen Datenprovider Sie verwenden - MySQL, SQL Server, OleDB usw. - die Konzepte sind dieselben.
Beispiel 1
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows AsInteger
con.Open()Dim sql ="SELECT * FROM tblfoobar_List"
da =New OleDbDataAdapter(sql, con)
da.Fill(ds,"foobar")
con.Close()
MaxRows = ds.Tables("foobar").Rows.Count ' Error
Nach wie vor wurde das dsDataset-Objekt deklariert, es wurde jedoch nie eine Instanz erstellt. Das DataAdapterwird ein vorhandenes füllen DataSet, kein erstellt. In diesem Fall warnt Sie die IDE , da dies dseine lokale Variable ist : Dies könnte passieren:
Wenn conder Compiler als Variable auf Modul- / Klassenebene deklariert wird, wie dies der Fall zu sein scheint, kann er nicht wissen, ob das Objekt durch eine vorgelagerte Prozedur erstellt wurde. Warnungen nicht ignorieren.
Ein Tippfehler ein Problem hier: Employeesvs Employee. Es wurde kein DataTableName "Mitarbeiter" erstellt, daher wurde ein NullReferenceExceptionErgebnis erzielt, bei dem versucht wurde, darauf zuzugreifen. Ein weiteres potenzielles Problem ist die Annahme, dass dies Itemsder Fall sein wird, wenn SQL eine WHERE-Klausel enthält.
Abhilfe
Da hierfür eine Tabelle verwendet Tables(0)wird , werden durch die Verwendung Rechtschreibfehler vermieden. Untersuchen Rows.Countkann auch helfen:
If ds.Tables(0).Rows.Count >0Then
txtID.Text = ds.Tables(0).Rows(0).Item(1)
txtID.Name = ds.Tables(0).Rows(0).Item(2)EndIf
Fillist eine Funktion, die die Anzahl der RowsBetroffenen zurückgibt, die auch getestet werden kann:
If da.Fill(ds,"Employees")>0Then...
Beispiel 3
Dim da AsNew OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)Dim ds AsNew DataSet
da.Fill(ds)If ds.Tables("TICKET_RESERVATION").Rows.Count >0Then
Das DataAdapterwird TableNameswie im vorherigen Beispiel gezeigt bereitgestellt, analysiert jedoch keine Namen aus der SQL- oder Datenbanktabelle. Als Ergebnis ds.Tables("TICKET_RESERVATION")verweist auf eine nicht vorhandene Tabelle.
Das Mittel ist das gleiche, referenzieren Sie die Tabelle nach Index:
Der Code wird nur getestet, Itemswährend beide myFoound Barmöglicherweise auch nichts sind. Das Mittel besteht darin, die gesamte Kette oder den gesamten Pfad von Objekten einzeln zu testen:
AndAlsoist wichtig. Nachfolgende Tests werden nicht durchgeführt, sobald die erste FalseBedingung erfüllt ist. Auf diese Weise kann der Code sicher eine Ebene nach der anderen in das Objekt (die Objekte) "bohren" myFoo.Barund erst dann auswerten, wenn (und wenn) myFoofestgestellt wurde, dass es gültig ist. Objektketten oder -pfade können beim Codieren komplexer Objekte sehr lang werden:
Hier myWebBrowseroder Documentkönnte nichts sein oder das formfld1Element kann nicht existieren.
UI-Steuerelemente
Dim cmd5 AsNew SqlCommand("select Cartons, Pieces, Foobar " _
&"FROM Invoice where invoice_no = '"& _
Me.ComboBox5.SelectedItem.ToString.Trim &"' And category = '"& _
Me.ListBox1.SelectedItem.ToString.Trim &"' And item_name = '"& _
Me.ComboBox2.SelectedValue.ToString.Trim &"' And expiry_date = '"& _
Me.expiry.Text &"'", con)
Dieser Code geht unter anderem nicht davon aus, dass der Benutzer möglicherweise etwas in einem oder mehreren UI-Steuerelementen nicht ausgewählt hat. ListBox1.SelectedItemkann gut sein Nothing, so ListBox1.SelectedItem.ToStringwird in einem NRE führen.
Abhilfe
Überprüfen Sie die Daten, bevor Sie sie verwenden (verwenden Sie auch Option Strictund SQL-Parameter):
Dim expiry As DateTime ' for text date validationIf(ComboBox5.SelectedItems.Count >0)AndAlso(ListBox1.SelectedItems.Count >0)AndAlso(ComboBox2.SelectedItems.Count >0)AndAlso(DateTime.TryParse(expiry.Text, expiry)Then'... do stuffElse
MessageBox.Show(...error message...)EndIf
Alternativ können Sie verwenden (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Visual Basic Forms
PublicClass Form1
Private NameBoxes =New TextBox(5){Controls("TextBox1"), _
Controls("TextBox2"), Controls("TextBox3"), _
Controls("TextBox4"), Controls("TextBox5"), _
Controls("TextBox6")}' same thing in a different format:Private boxList AsNew List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}' Immediate NRE:Private somevar AsString=Me.Controls("TextBox1").Text
Dies ist ein ziemlich üblicher Weg, um ein NRE zu erhalten. In C # meldet die IDE abhängig davon, wie sie codiert ist, dass Controlssie im aktuellen Kontext nicht vorhanden ist oder "nicht auf ein nicht statisches Mitglied verweisen kann". Bis zu einem gewissen Grad handelt es sich also nur um eine VB-Situation. Es ist auch komplex, weil es zu einer Ausfallkaskade führen kann.
Die Arrays und Sammlungen können auf diese Weise nicht initialisiert werden. Dieser Initialisierungscode wird ausgeführt, bevor der Konstruktor das Formoder das erstellt Controls. Als Ergebnis:
Listen und Sammlung sind einfach leer
Das Array enthält fünf Elemente von Nothing
Die somevarZuweisung führt zu einer sofortigen NRE, da Nothing keine .TextEigenschaft hat
Wenn Sie später auf Array-Elemente verweisen, erhalten Sie eine NRE. Wenn Sie dies Form_Loadaufgrund eines seltsamen Fehlers tun , meldet die IDE die Ausnahme möglicherweise nicht , wenn sie auftritt. Die Ausnahme wird später angezeigt, wenn Ihr Code versucht, das Array zu verwenden. Diese "stille Ausnahme" wird in diesem Beitrag detailliert beschrieben . Für unsere Zwecke ist der Schlüssel, dass, wenn beim Erstellen eines Formulars ( Sub Newoder Form LoadEreignisses) etwas Katastrophales passiert , Ausnahmen möglicherweise nicht gemeldet werden, der Code die Prozedur beendet und nur das Formular anzeigt.
Da kein anderer Code in Ihrem Sub Newoder Form LoadEreignis nach dem NRE ausgeführt wird, können viele andere Dinge nicht initialisiert werden.
Sub Form_Load(..._
'...Dim name AsString= NameBoxes(2).Text ' NRE' ...' More code (which will likely not be executed)' ...EndSub
Beachten Sie, dass dies für alle Steuerungs- und Komponentenreferenzen gilt, die diese illegal machen, wo sie sind:
Es ist merkwürdig , dass VB keine Warnung liefern, aber die Lösung ist zu erklären , die Behälter auf Formularebene, sondern initialisieren sie in Form Load - Ereignishandler , wenn die Kontrollen nicht existieren. Dies kann erfolgen, Sub Newsolange sich Ihr Code nach dem InitializeComponentAufruf befindet:
' Module level declarationPrivate NameBoxes as TextBox()Private studentName AsString' Form Load, Form Shown or Sub New:'' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes =New TextBox(){Me.Controls("TextBox1"),Me.Controls("TestBox2"),...)
studentName = TextBox32.Text ' For simple control references
Der Array-Code ist möglicherweise noch nicht aus dem Wald. Alle Steuerelemente, die sich in einem Containersteuerelement befinden (wie ein GroupBoxoder Panel), werden nicht in gefunden Me.Controls. Sie befinden sich in der Controls-Auflistung dieses Panels oder dieser GroupBox. Ein Steuerelement wird auch nicht zurückgegeben, wenn der Steuerelementname falsch geschrieben ist ( "TeStBox2"). In solchen Fällen Nothingwird erneut in diesen Array-Elementen gespeichert und es entsteht eine NRE, wenn Sie versuchen, darauf zu verweisen.
Diese sollten jetzt leicht zu finden sein, da Sie wissen, wonach Sie suchen:
"Button2" befindet sich auf a Panel
Abhilfe
Verwenden Sie anstelle indirekter namentlicher Verweise in der Formularsammlung Controlsdie Steuerelementreferenz:
' DeclarationPrivate NameBoxes As TextBox()' Initialization - simple and easy to read, hard to botch:
NameBoxes =New TextBox(){TextBox1, TextBox2,...)' Initialize a List
NamesList =New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})' or
NamesList =New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})
Funktion, die nichts zurückgibt
Private bars AsNew List(Of Bars)' Declared and createdPublicFunction BarList()As List(Of Bars)
bars.Clear
If someCondition ThenFor n AsInteger=0to someValue
bars.Add(GetBar(n))Next n
ElseExitFunctionEndIfReturn bars
EndFunction
Dies ist ein Fall, in dem die IDE Sie warnt, dass nicht alle Pfade einen Wert zurückgeben und NullReferenceExceptionmöglicherweise ein Ergebnis resultiert . Sie können die Warnung unterdrücken durch Ersetzen Exit Functionmit Return Nothing, aber das löst nicht das Problem. Alles, was versucht, die Rückgabe zu verwenden, someCondition = Falseführt zu einem NRE:
bList = myFoo.BarList()ForEach b As Bar in bList ' EXCEPTION...
Abhilfe
Ersetzen Sie Exit Functionin der Funktion durch Return bList. Das Zurückgeben eines LeerzeichensList ist nicht dasselbe wie das Zurückgeben Nothing. Wenn die Möglichkeit besteht, dass ein zurückgegebenes Objekt vorhanden ist Nothing, testen Sie es , bevor Sie es verwenden:
Ein schlecht implementierter Try / Catch kann verbergen, wo das Problem liegt, und zu neuen führen:
Dim dr As SqlDataReader
TryDim lnk As LinkButton = TryCast(sender, LinkButton)Dim gr As GridViewRow =DirectCast(lnk.NamingContainer, GridViewRow)Dim eid AsString= GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username")= eid
sqlQry ="select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username='"& eid &"'"If connection.State <> ConnectionState.Open Then
connection.Open()EndIf
command =New SqlCommand(sqlQry, connection)'More code fooing and barring
dr = command.ExecuteReader()If dr.Read()Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))...EndIf
mpe.Show()CatchFinally
command.Dispose()
dr.Close()' <-- NRE
connection.Close()EndTry
Dies ist ein Fall, in dem ein Objekt nicht wie erwartet erstellt wird, sondern auch die Gegennutzen eines leeren Objekts demonstriert Catch.
Es gibt ein zusätzliches Komma in der SQL (nach 'Mailadresse'), was zu einer Ausnahme bei führt .ExecuteReader. Nachdem der Catchnichts tut, Finallyversucht er eine Bereinigung durchzuführen, aber da Sie kein CloseNullobjekt können DataReader, NullReferenceExceptionergibt sich ein brandneues Ergebnis.
Ein leerer CatchBlock ist der Spielplatz des Teufels. Dieser OP war verblüfft, warum er eine NRE im FinallyBlock bekam. In anderen Situationen kann ein Leerlauf Catchdazu führen, dass etwas anderes viel weiter stromabwärts durcheinander gerät und Sie Zeit damit verbringen, die falschen Dinge am falschen Ort für das Problem zu suchen. (Die oben beschriebene "stille Ausnahme" bietet den gleichen Unterhaltungswert.)
Abhilfe
Verwenden Sie keine leeren Try / Catch-Blöcke - lassen Sie den Code abstürzen, damit Sie a) die Ursache identifizieren, b) den Ort identifizieren und c) ein geeignetes Mittel anwenden können. Try / Catch-Blöcke sollen keine Ausnahmen vor der Person verbergen, die für die Behebung dieser Probleme eindeutig qualifiziert ist - dem Entwickler.
DBNull ist nicht dasselbe wie Nothing
ForEach row As DataGridViewRow In dgvPlanning.Rows
IfNot IsDBNull(row.Cells(0).Value)Then...
Die IsDBNullFunktion wird verwendet, um zu testen, ob ein Wert gleich ist System.DBNull: Von MSDN:
Der Wert System.DBNull gibt an, dass das Objekt fehlende oder nicht vorhandene Daten darstellt. DBNull ist nicht dasselbe wie Nothing, was darauf hinweist, dass eine Variable noch nicht initialisiert wurde.
Abhilfe
If row.Cells(0) IsNot NothingThen...
Nach wie vor können Sie auf Nothing und dann auf einen bestimmten Wert testen:
Dim getFoo =(From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
IfNot IsDBNull(getFoo)ThenIf IsDBNull(getFoo.user_id)Then
txtFirst.Text = getFoo.first_name
Else...
FirstOrDefaultGibt das erste Element oder den Standardwert zurück, der Nothingfür Referenztypen gilt und niemals DBNull:
If getFoo IsNot NothingThen...
Kontrollen
Dim chk As CheckBox
chk =CType(Me.Controls(chkName), CheckBox)If chk.Checked ThenReturn chk
EndIf
Wenn ein CheckBoxwith chkNamenicht gefunden werden kann (oder in a vorhanden ist GroupBox), chkist Nothing und der Versuch, auf eine Eigenschaft zu verweisen, führt zu einer Ausnahme.
Abhilfe
If(chk IsNot Nothing)AndAlso(chk.Checked)Then...
Die DataGridView
Die DGV hat einige Macken, die regelmäßig gesehen werden:
Wenn dies der Fall dgvBooksist AutoGenerateColumns = True, werden die Spalten erstellt, aber nicht benannt, sodass der obige Code fehlschlägt, wenn er nach Namen referenziert wird.
Abhilfe
Benennen Sie die Spalten manuell oder referenzieren Sie sie nach Index:
Wenn Sie DataGridViewhat AllowUserToAddRowsals True(Standardeinstellung), die Cellsin dem Rohling / neue Zeile am unteren Rande wird alle enthalten Nothing. Die meisten Versuche, den Inhalt zu verwenden (zum Beispiel ToString), führen zu einer NRE.
Abhilfe
Verwenden Sie eine For/EachSchleife und testen Sie die IsNewRowEigenschaft, um festzustellen, ob es sich um die letzte Zeile handelt. Dies funktioniert unabhängig davon, ob AllowUserToAddRowses wahr ist oder nicht:
ForEach r As DataGridViewRow in myDGV.Rows
If r.IsNewRow =FalseThen' ok to use this row
Wenn Sie eine For nSchleife verwenden, ändern Sie die Zeilenanzahl oder verwenden Sie, Exit Forwenn IsNewRowtrue ist.
My.Settings (StringCollection)
Unter bestimmten Umständen kann der Versuch, ein Element zu verwenden, von My.Settingsdem StringCollectiona stammt, bei der ersten Verwendung zu einer NullReferenz führen. Die Lösung ist dieselbe, aber nicht so offensichtlich. Erwägen:
My.Settings.FooBars.Add("ziggy")' foobars is a string collection
Da VB die Einstellungen für Sie verwaltet, ist zu erwarten, dass die Sammlung initialisiert wird. Dies ist jedoch nur möglich, wenn Sie zuvor einen ersten Eintrag zur Sammlung hinzugefügt haben (im Einstellungseditor). Da die Sammlung (anscheinend) beim Hinzufügen eines Elements initialisiert wird, bleibt sie erhaltenNothing wenn im Einstellungseditor keine Elemente zum Hinzufügen vorhanden sind.
Abhilfe
Initialisieren Sie die Einstellungssammlung im LoadEreignishandler des Formulars , falls erforderlich.
If My.Settings.FooBars IsNothingThen
My.Settings.FooBars =New System.Collections.Specialized.StringCollection
EndIf
In der Regel muss die SettingsSammlung nur beim ersten Ausführen der Anwendung initialisiert werden. Eine alternative Abhilfe besteht darin, Ihrer Sammlung unter Projekt -> Einstellungen | einen Anfangswert hinzuzufügen FooBars , speichern Sie das Projekt und entfernen Sie den gefälschten Wert.
Wichtige Punkte
Sie haben wahrscheinlich den NewOperator vergessen .
oder
Etwas, von dem Sie angenommen haben, dass es fehlerfrei funktioniert, um ein initialisiertes Objekt an Ihren Code zurückzugeben, hat dies nicht getan.
Ignorieren Sie Compiler-Warnungen nicht (jemals) und verwenden Sie sie Option Strict On(immer).
Ein anderes Szenario ist, wenn Sie ein Nullobjekt in einen Werttyp umwandeln . Zum Beispiel der folgende Code:
object o =null;DateTime d =(DateTime)o;
Es wird einen NullReferenceExceptionauf die Besetzung werfen. Im obigen Beispiel scheint dies ziemlich offensichtlich zu sein, aber dies kann in komplizierteren Szenarien geschehen, in denen das Nullobjekt von einem Code zurückgegeben wurde, den Sie nicht besitzen, und die Umwandlung beispielsweise von einem automatischen System generiert wird.
Ein Beispiel hierfür ist dieses einfache ASP.NET-Bindungsfragment mit dem Kalendersteuerelement:
Hier SelectedDatehandelt es sich tatsächlich um eine Eigenschaft - vom DateTimeTyp - vom Typ CalendarWeb Control, und die Bindung könnte perfekt etwas Null zurückgeben. Der implizite ASP.NET-Generator erstellt einen Code, der dem obigen Cast-Code entspricht. Und dies führt zu einem Problem NullReferenceException, das ziemlich schwer zu erkennen ist, da es in von ASP.NET generiertem Code liegt, der sich gut kompilieren lässt ...
Das wird den Fehler auslösen, denn während ich die Variable " connection" deklariert habe , zeigt sie auf nichts. Wenn ich versuche, das Mitglied " Open" aufzurufen , gibt es keinen Verweis, den es lösen könnte, und es wird den Fehler auslösen.
So vermeiden Sie diesen Fehler:
Initialisieren Sie Ihre Objekte immer, bevor Sie versuchen, etwas damit zu tun.
Wenn Sie nicht sicher sind, ob das Objekt null ist, überprüfen Sie es mit object == null.
Das Resharper-Tool von JetBrains identifiziert jede Stelle in Ihrem Code, an der möglicherweise ein Nullreferenzfehler auftritt, sodass Sie eine Nullprüfung durchführen können. Dieser Fehler ist meiner Meinung nach die häufigste Fehlerquelle.
Das Resharper-Tool von JetBrains identifiziert jede Stelle in Ihrem Code, an der möglicherweise ein Nullreferenzfehler auftritt. Das ist falsch. Ich habe eine Lösung ohne diese Erkennung, aber der Code führt gelegentlich zur Ausnahme. Ich vermute, dass es gelegentlich nicht nachweisbar ist - zumindest von ihnen -, wenn es um Multithreading geht, aber ich kann keine weiteren Kommentare abgeben, da ich den Ort meines Fehlers noch nicht identifiziert habe.
j riv
Aber wie man es löst, wenn die NullReferenceException in usign HttpContext.Current.Responce.Clear () kommt. Es wird durch keine der oben genannten Lösungen gelöst. Denn beim Erstellen des Objektobjekts HttpContext tritt der Fehler "Überladungsauflösung fehlgeschlagen, da kein zugängliches 'Neu' diese Anzahl von Argumenten akzeptiert.
Sunny Sandeep
157
Dies bedeutet, dass Ihr Code eine Objektreferenzvariable verwendet hat, die auf null gesetzt wurde (dh keine tatsächliche Objektinstanz referenziert hat).
Um den Fehler zu vermeiden, sollten Objekte, die null sein könnten, vor der Verwendung auf null getestet werden.
if(myvar !=null){// Go ahead and use myvar
myvar.property=...}else{// Whoops! myvar is null and cannot be used without first// assigning it to an instance reference// Attempting to use myvar here will result in NullReferenceException}
Beachten Sie, dass die Ursache in .NET unabhängig vom Szenario immer dieselbe ist:
Sie versuchen, eine Referenzvariable zu verwenden, deren Wert Nothing/ ist null. Wenn der Wert Nothing/ istnull für die Referenzvariable ist, bedeutet dies, dass er keinen Verweis auf eine Instanz eines Objekts enthält, das auf dem Heap vorhanden ist.
Sie haben der Variablen entweder nie etwas zugewiesen, nie eine Instanz des der Variablen zugewiesenen Werts erstellt oder die Variable auf Nothing/ nullmanuell gesetzt oder eine Funktion aufgerufen, die die Variable auf Nothing/ nullfür Sie gesetzt hat.
Ein Beispiel für diese Ausnahme ist: Wenn Sie versuchen, etwas zu überprüfen, ist dies null.
Zum Beispiel:
string testString =null;//Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)if(testString.Length==0)// Throws a nullreferenceexception{//Do something}
Die .NET-Laufzeit löst eine NullReferenceException aus, wenn Sie versuchen, eine Aktion für etwas auszuführen, das nicht instanziiert wurde, z. B. den obigen Code.
Im Vergleich zu einer ArgumentNullException, die normalerweise als Abwehrmaßnahme ausgelöst wird, wenn eine Methode erwartet, dass das, was an sie übergeben wird, nicht null ist.
C # 8.0 führt nullbare Referenztypen und nicht nullbare Referenztypen ein . Daher müssen nur nullfähige Referenztypen überprüft werden, um eine NullReferenceException zu vermeiden .
Wenn Sie keinen Referenztyp initialisiert haben und eine seiner Eigenschaften festlegen oder lesen möchten, wird eine NullReferenceException ausgelöst .
Beispiel:
Person p =null;
p.Name="Harry";// NullReferenceException occurs here.
Sie können dies einfach vermeiden, indem Sie überprüfen, ob die Variable nicht null ist:
Person p =null;if(p!=null){
p.Name="Harry";// Not going to run to this point}
Um vollständig zu verstehen , warum ein Nullreferenceexception geworfen wird, ist es wichtig , den Unterschied zwischen wissen , Werttypen und [Referenztypen] [3].
Also, wenn Sie es zu tun Werttypen können NullReferenceExceptions nicht auftreten. Allerdings müssen Sie beim Umgang mit Referenztypen wachsam sein !
Nur Referenztypen können, wie der Name schon sagt, Referenzen enthalten oder buchstäblich auf nichts (oder 'null') verweisen. Während Werttypen immer einen Wert enthalten.
-1: Da die Frage "Was ist eine NullReferenceException" lautet, sind Werttypen nicht relevant.
John Saunders
21
@ John Saunders: Ich bin anderer Meinung. Als Softwareentwickler ist es sehr wichtig, zwischen Wert- und Referenztypen unterscheiden zu können. Andernfalls wird überprüft, ob Ganzzahlen null sind.
Fabian Bigler
5
Richtig, nur nicht im Zusammenhang mit dieser Frage.
John Saunders
4
Danke für den Tipp. Ich habe es ein bisschen verbessert und oben ein Beispiel hinzugefügt. Ich denke immer noch, dass es nützlich ist, Referenz- und Werttypen zu erwähnen.
Fabian Bigler
5
Ich denke, Sie haben nichts hinzugefügt, was nicht in den anderen Antworten enthalten war, da die Frage einen Referenztyp voraussetzt.
John Saunders
78
Ein weiterer Fall, in dem NullReferenceExceptionsdies passieren kann, ist die (falsche) Verwendung des asOperators :
Hier Bookund Carsind inkompatible Typen; a Carkann nicht konvertiert / in a umgewandelt werden Book. Wenn diese Besetzung fehlschlägt, askehrt sie zurück null. Die Verwendung mybookdanach bewirkt aNullReferenceException .
Im Allgemeinen sollten Sie eine Besetzung verwenden oder aswie folgt:
Wenn Sie erwarten, dass die Typkonvertierung immer erfolgreich ist (dh Sie wissen, was das Objekt im Voraus sein sollte), sollten Sie eine Umwandlung verwenden:
ComicBook cb =(ComicBook)specificBook;
Wenn Sie sich über den Typ nicht sicher sind, aber versuchen möchten, ihn als bestimmten Typ zu verwenden, verwenden Sie as:
Dies kann beim Entpacken einer Variablen häufig vorkommen. Ich finde, dass es in Ereignishandlern häufig vorkommt, nachdem ich den Typ des UI-Elements geändert habe, aber vergessen habe, den Code-Behind zu aktualisieren.
Brendan
65
Sie verwenden das Objekt, das die Nullwertreferenz enthält. Es gibt also eine Null-Ausnahme. Im Beispiel ist der Zeichenfolgenwert null, und bei der Überprüfung seiner Länge ist die Ausnahme aufgetreten.
Beispiel:
stringvalue=null;if(value.Length==0)// <-- Causes exception{Console.WriteLine(value);// <-- Never reached}
Der Ausnahmefehler ist:
Unbehandelte Ausnahme:
System.NullReferenceException: Objektreferenz nicht auf eine Instanz eines Objekts festgelegt. bei Program.Main ()
Wie tief! Ich habe die Nullkonstante nie als Referenzwert angesehen. So abstrahiert C # einen "NullPointer", oder? B / c, wie ich mich in C ++ erinnere, kann eine NPE durch Dereferenzieren eines nicht initialisierten Zeigers (dh Ref-Typ in c #) verursacht werden, dessen Standardwert zufällig eine Adresse ist, die diesem Prozess nicht zugewiesen ist (in vielen Fällen wäre dies 0, Besonders in späteren Versionen von C ++, die eine automatische Initialisierung durchgeführt haben, die zum Betriebssystem gehört - f damit und die Beeotch (oder fangen Sie einfach den Sigkill, mit dem das Betriebssystem Ihren Prozess angreift)).
Samis
64
Während die Ursachen für NullReferenceExceptions und Ansätze zur Vermeidung / Behebung einer solchen Ausnahme in anderen Antworten behandelt wurden, haben viele Programmierer noch nicht gelernt, wie solche Ausnahmen während der Entwicklung unabhängig voneinander debuggt werden können.
Wenn nun die NullReferenceException ausgelöst (oder nicht behandelt) wird, stoppt der Debugger in der Zeile, in der die Ausnahme aufgetreten ist (erinnern Sie sich an den oben festgelegten Regelsatz?). Manchmal ist der Fehler leicht zu erkennen.
In fortgeschritteneren Fällen, wie den folgenden, müssen Sie eine der oben genannten Techniken (Watch oder Immediate Windows) verwenden, um die Ausdrücke zu überprüfen, um festzustellen, ob str1 null oder str2null waren.
var x = str1.Trim()+ str2.Trim();
Einmal wo die Ausnahme throw ist lokalisiert worden, es Grund rückwärts in der Regel trivial ist, um herauszufinden , wo der Nullwert [falsch] eingeführt wurde -
Nehmen Sie sich Zeit, um die Ursache der Ausnahme zu verstehen. Auf Nullausdrücke prüfen. Überprüfen Sie die vorherigen Ausdrücke, die zu solchen Nullausdrücken hätten führen können. Fügen Sie Haltepunkte hinzu und führen Sie das Programm entsprechend durch.Verwenden Sie den Debugger.
1 Wenn Break on Throws zu aggressiv ist und der Debugger auf einer NPE in der .NET- oder Drittanbieter-Bibliothek stoppt, kann Break on User-Unhandled verwendet werden, um die abgefangenen Ausnahmen zu begrenzen. Darüber hinaus führt VS2012 Just My Code ein, das ich ebenfalls aktivieren möchte .
Wenn Sie mit aktiviertem Just My Code debuggen, unterscheidet sich das Verhalten geringfügig. Wenn Just My Code aktiviert ist, ignoriert der Debugger CLR-Ausnahmen (Common Language Runtime) der ersten Chance, die außerhalb von My Code ausgelöst werden und My Code nicht durchlaufen
object o =null;DateTime d =(DateTime)o;// NullReferenceException
wobei eine Unboxing- Konvertierung (Umwandlung) vonobject (oder von einer der Klassen System.ValueTypeoder oder System.Enumoder von einem Schnittstellentyp) in einen Werttyp (außer Nullable<>) an sich das ergibtNullReferenceException .
In der anderen Richtung wird eine boxing Umwandlung von a Nullable<>welches HasValuegleich falsezu einem Referenz - Typ kann eine geben nullReferenz , die auf ein später führen kann NullReferenceException. Das klassische Beispiel ist:
DateTime? d =null;var s = d.ToString();// OK, no exception (no boxing), returns ""var t = d.GetType();// Bang! d is boxed, NullReferenceException
Manchmal geschieht das Boxen auf andere Weise. Zum Beispiel mit dieser nicht generischen Erweiterungsmethode:
Hinzufügen eines Falls, in dem der Klassenname für die im Entitätsframework verwendete Entität mit dem Klassennamen für eine Webformular-CodeBehind-Datei identisch ist.
Angenommen, Sie haben ein Webformular Contact.aspx, dessen Codebehind-Klasse Contact ist, und Sie haben einen Entitätsnamen Contact.
Der folgende Code löst dann eine NullReferenceException aus, wenn Sie context.SaveChanges () aufrufen.
Contact contact =newContact{Name="Abhinav"};var context =newDataContext();
context.Contacts.Add(contact);
context.SaveChanges();// NullReferenceException at this line
Der Fehler tritt auf, wenn sich sowohl die Entität als auch die Codebehind-Klasse im selben Namespace befinden. Um dies zu beheben, benennen Sie die Entitätsklasse oder die Codebehind-Klasse für Contact.aspx um.
Grund
Ich bin mir immer noch nicht sicher über den Grund. Aber wenn eine der Entitätsklassen System.Web.UI.Page erweitert, tritt dieser Fehler auf.
Ein weiterer allgemeiner Fall, in dem diese Ausnahme auftreten kann, besteht darin, Klassen während des Komponententests zu verspotten. Unabhängig vom verwendeten Verspottungsframework müssen Sie sicherstellen, dass alle geeigneten Ebenen der Klassenhierarchie ordnungsgemäß verspottet sind. Insbesondere alle Eigenschaften vonHttpContext verspottet werden, auf die der zu testende Code verweist.
Ich habe eine andere Perspektive als darauf zu antworten. Diese Art von Antworten "Was kann ich noch tun, um dies zu vermeiden? "
Wenn ein Controller über verschiedene Ebenen hinweg arbeitet , beispielsweise in einer MVC-Anwendung, benötigt er Dienste, um Geschäftsvorgänge aufzurufen. In solchen Szenarien kann der Abhängigkeitsinjektionscontainer zum Initialisieren der Dienste verwendet werden, um die NullReferenceException zu vermeiden . Das bedeutet, dass Sie sich keine Gedanken über die Überprüfung auf Null machen müssen und die Dienste einfach vom Controller aus aufrufen müssen, als ob sie immer als Singleton oder Prototyp verfügbar (und initialisiert) wären.
publicclassMyController{privateServiceA serviceA;privateServiceB serviceB;publicMyController(ServiceA serviceA,ServiceB serviceB){this.serviceA = serviceA;this.serviceB = serviceB;}publicvoidMyMethod(){// We don't need to check null because the dependency injection container // injects it, provided you took care of bootstrapping it.var someObject = serviceA.DoThis();}}
-1: Dies behandelt nur ein einziges Szenario - das von nicht initialisierten Abhängigkeiten. Dies ist ein Minderheitenszenario für NullReferenceException. Die meisten Fälle sind einfache Missverständnisse darüber, wie Objekte funktionieren. Am häufigsten sind andere Situationen, in denen der Entwickler davon ausgegangen ist, dass das Objekt automatisch initialisiert wird.
John Saunders
Die Abhängigkeitsinjektion wird im Allgemeinen nicht verwendet, um NullReferenceException zu vermeiden. Ich glaube nicht, dass Sie hier ein allgemeines Szenario gefunden haben. In jedem Fall werde ich die Ablehnung entfernen , wenn Sie Ihre Antwort so bearbeiten, dass sie eher dem Stil von stackoverflow.com/a/15232518/76337 entspricht.
John Saunders
38
In Bezug auf "Was soll ich dagegen tun?" Kann es viele Antworten geben.
Eine "formellere" Möglichkeit, solche Fehlerbedingungen während der Entwicklung zu verhindern, besteht darin, das Design in Ihrem Code vertraglich anzuwenden . Diese Mittel müssen Sie Setklasse Invarianten und / oder auch Funktion / Methode Vorbedingungen und Nachbedingungen auf Ihrem System, während der Entwicklung.
Kurz gesagt, Klasseninvarianten stellen sicher, dass es in Ihrer Klasse einige Einschränkungen gibt, die bei normaler Verwendung nicht verletzt werden (und daher wird die Klasse nicht in einen inkonsistenten Zustand versetzt). Voraussetzungen bedeuten, dass Daten, die als Eingabe für eine Funktion / Methode angegeben werden, bestimmten festgelegten Einschränkungen folgen und diese niemals verletzen müssen. Nachbedingungen bedeuten, dass eine Ausgabe von Funktionen / Methoden den festgelegten Einschränkungen erneut folgen muss, ohne sie jemals zu verletzen. Vertragsbedingungen sollten während der Ausführung eines fehlerfreien Programms niemals verletzt werden. Daher wird das vertragliche Design in der Praxis im Debug-Modus überprüft und in Releases deaktiviert , um die Leistung des entwickelten Systems zu maximieren.
Auf diese Weise können Sie NullReferenceExceptionFälle vermeiden , die auf eine Verletzung der festgelegten Einschränkungen zurückzuführen sind. Wenn Sie beispielsweise eine Objekteigenschaft Xin einer Klasse verwenden und später versuchen, eine ihrer Methoden aufzurufen, Xdie einen Nullwert hat, führt dies zu NullReferenceException:
public X {get;set;}publicvoidInvokeX(){
X.DoSomething();// if X value is null, you will get a NullReferenceException}
Wenn Sie jedoch als Methodenvoraussetzung "Eigenschaft X darf niemals einen Nullwert haben" festlegen, können Sie das zuvor beschriebene Szenario verhindern:
//Using code contracts:[ContractInvariantMethod]protectedvoidObjectInvariant(){Contract.Invariant( X !=null);//...}
Aus diesem Grund ist das Code Contracts- Projekt für .NET-Anwendungen vorhanden.
Alternativ kann das vertragliche Design unter Verwendung von Behauptungen angewendet werden .
Ich dachte, dies hinzuzufügen, da niemand dies erwähnte, und soweit es als Ansatz existiert, war meine Absicht, das Thema zu bereichern.
Nick Louloudakis
2
Vielen Dank für die Bereicherung des Themas. Ich habe meine Meinung zu Ihrer Hinzufügung abgegeben. Jetzt können andere das Gleiche tun.
John Saunders
2
Ich dachte, dies sei eine lohnende Ergänzung des Themas, da dies ein hoch angesehener Thread ist. Ich habe schon einmal von Codeverträgen gehört und dies war eine gute Erinnerung daran, sie zu verwenden.
VoteCoffee
36
A NullReferenceExceptionwird ausgelöst, wenn wir versuchen, auf Eigenschaften eines Nullobjekts zuzugreifen, oder wenn ein Zeichenfolgenwert leer wird und wir versuchen, auf Zeichenfolgenmethoden zuzugreifen.
Zum Beispiel:
Wenn auf eine Zeichenfolgenmethode einer leeren Zeichenfolge zugegriffen wird:
Das ist falsch. String.Empty.ToLower()löst keine Nullreferenzausnahme aus. Es stellt eine tatsächliche Zeichenfolge dar, wenn auch eine leere (dh ""). Da dies ein Objekt zum Aufrufen hat ToLower(), wäre es nicht sinnvoll, dort eine Nullreferenzausnahme auszulösen.
Kjartan
31
TL; DR: Versuchen Sie es mit Html.Partialanstelle vonRenderpage
Ich habe Object reference not set to an instance of an objectfestgestellt , dass ich versucht habe, eine Ansicht in einer Ansicht zu rendern , indem ich ihr ein Modell wie folgt gesendet habe:
@{MyEntity M =newMyEntity();}@RenderPage("_MyOtherView.cshtml", M);// error in _MyOtherView, the Model was Null
Das Debuggen zeigte, dass das Modell in MyOtherView Null war. Bis ich es geändert habe zu:
@{MyEntity M =newMyEntity();}@Html.Partial("_MyOtherView.cshtml", M);
Und es hat funktioniert.
Außerdem musste ich nicht damit Html.Partialbeginnen, dass Visual Studio manchmal fehlerhaft aussehende, schnörkellose Linien darunter wirft, Html.Partialwenn es sich in einer anders konstruierten foreachSchleife befindet, obwohl es nicht wirklich ein Fehler ist:
@inheritsSystem.Web.Mvc.WebViewPage@{ViewBag.Title="Entity Index";List<MyEntity>MyEntities=newList<MyEntity>();MyEntities.Add(newMyEntity());MyEntities.Add(newMyEntity());MyEntities.Add(newMyEntity());}<div>@{foreach(var M inMyEntities){// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?@Html.Partial("MyOtherView.cshtml");}}</div>
Aber ich konnte die Anwendung ohne Probleme mit diesem "Fehler" ausführen. Ich konnte den Fehler beseitigen, indem ich die Struktur der foreachSchleife so änderte :
@foreach(var M inMyEntities){...}
Obwohl ich das Gefühl habe, dass Visual Studio das kaufmännische Und und die Klammern falsch gelesen hat.
Bitte zeigen Sie auch, welche Zeile die Ausnahme ausgelöst hat und warum.
John Saunders
Der Fehler trat in MyOtherView.cshtml auf, den ich hier nicht aufgenommen habe, da das Modell nicht ordnungsgemäß gesendet wurde (es war Null), sodass ich wusste, dass der Fehler darin bestand, wie ich das Modell gesendet habe .
Travis Heeter
22
Was können Sie dagegen tun?
Hier gibt es viele gute Antworten, die erklären, was eine Nullreferenz ist und wie man sie debuggt. Es gibt jedoch nur sehr wenige Möglichkeiten, um das Problem zu verhindern oder zumindest das Auffinden zu erleichtern.
Überprüfen Sie die Argumente
Beispielsweise können Methoden die verschiedenen Argumente überprüfen, um festzustellen, ob sie null sind, und eine auslösen ArgumentNullException, eine Ausnahme, die offensichtlich genau für diesen Zweck erstellt wurde.
Der Konstruktor für das ArgumentNullExceptionEven verwendet den Namen des Parameters und eine Nachricht als Argumente, damit Sie dem Entwickler genau mitteilen können, wo das Problem liegt.
publicvoidDoSomething(MyObject obj){if(obj ==null){thrownewArgumentNullException("obj","Need a reference to obj.");}}
Verwenden Sie Tools
Es gibt auch mehrere Bibliotheken, die helfen können. "Resharper" kann Sie beispielsweise beim Schreiben von Code warnen , insbesondere wenn Sie das folgende Attribut verwenden: NotNullAttribute
Es gibt "Microsoft Code Contracts", in denen Sie Syntax wie verwenden Contract.Requires(obj != null) der Sie Laufzeit- und Kompilierungsprüfungen durchführen können: Einführung in Code Contracts .
Es gibt auch "PostSharp", mit dem Sie einfach folgende Attribute verwenden können:
publicvoidDoSometing([NotNull] obj)
Auf diese Weise wird PostSharp zur objLaufzeit auf Null gesetzt , wenn es Teil Ihres Erstellungsprozesses ist . Sehen: PostSharp-Nullprüfung
Plain Code-Lösung
Oder Sie können Ihren eigenen Ansatz jederzeit mit einfachem altem Code codieren. Zum Beispiel ist hier eine Struktur, mit der Sie Nullreferenzen abfangen können. Es ist nach dem gleichen Konzept modelliert wie Nullable<T>:
[System.Diagnostics.DebuggerNonUserCode]publicstructNotNull<T>where T:class{private T _value;public T Value{get{if(_value ==null){thrownewException("null value not allowed");}return _value;}set{if(value==null){thrownewException("null value not allowed.");}
_value =value;}}publicstaticimplicitoperator T(NotNull<T> notNullValue){return notNullValue.Value;}publicstaticimplicitoperatorNotNull<T>(T value){returnnewNotNull<T>{Value=value};}}
Sie würden sehr ähnlich wie Sie verwenden Nullable<T>, außer mit dem Ziel, genau das Gegenteil zu erreichen - nicht zuzulassen null. Hier sind einige Beispiele:
NotNull<Person> person =null;// throws exceptionNotNull<Person> person =newPerson();// OKNotNull<Person> person =GetPerson();// throws exception if GetPerson() returns null
NotNull<T>wird implizit von und nach gegossen, Tsodass Sie es fast überall dort verwenden können, wo Sie es benötigen. Sie können beispielsweise ein PersonObjekt an eine Methode übergeben, die Folgendes verwendet NotNull<Person>:
Person person =newPerson{Name="John"};WriteName(person);publicstaticvoidWriteName(NotNull<Person> person){Console.WriteLine(person.Value.Name);}
Wie Sie oben wie bei nullable sehen können, würden Sie über die ValueEigenschaft auf den zugrunde liegenden Wert zugreifen . Alternativ können Sie eine explizite oder implizite Umwandlung verwenden. Sie können ein Beispiel mit dem folgenden Rückgabewert sehen:
Person person =GetPerson();publicstaticNotNull<Person>GetPerson(){returnnewPerson{Name="John"};}
Oder Sie können es sogar verwenden, wenn die Methode T(in diesem Fall Person) nur durch eine Umwandlung zurückgegeben wird. Der folgende Code möchte beispielsweise nur den obigen Code:
Person person =(NotNull<Person>)GetPerson();publicstaticPersonGetPerson(){returnnewPerson{Name="John"};}
Mit Erweiterung kombinieren
Kombinieren Sie NotNull<T>mit einer Erweiterungsmethode und Sie können noch mehr Situationen abdecken. Hier ist ein Beispiel, wie die Erweiterungsmethode aussehen kann:
[System.Diagnostics.DebuggerNonUserCode]publicstaticclassNotNullExtension{publicstatic T NotNull<T>(this T @this)where T:class{if(@this==null){thrownewException("null value not allowed");}return@this;}}
Und hier ist ein Beispiel, wie es verwendet werden könnte:
var person =GetPerson().NotNull();
GitHub
Als Referenz habe ich den obigen Code auf GitHub verfügbar gemacht. Sie finden ihn unter:
In C # 6.0 wurde der "nullbedingte Operator" eingeführt, der dabei ein wenig hilft. Mit dieser Funktion können Sie auf verschachtelte Objekte verweisen. Wenn eines davon einer ist, wird nullder gesamte Ausdruck zurückgegeben null.
Dies reduziert die Anzahl der Nullprüfungen, die Sie in einigen Fällen durchführen müssen. Die Syntax besteht darin, vor jedem Punkt ein Fragezeichen zu setzen. Nehmen Sie zum Beispiel den folgenden Code:
var address = country?.State?.County?.City;
Stellen Sie sich vor, es countryhandelt sich um ein Objekt vom Typ Countrymit einer Eigenschaft namens Stateusw. Wenn country, State, Countyoder Cityist nulldann address will benull . Therefore you only have to check whetherAdresse isnull`.
Es ist eine großartige Funktion, aber es gibt Ihnen weniger Informationen. Es macht nicht klar, welche der 4 null ist.
Eingebaut wie Nullable?
C # hat eine nette Abkürzung für Nullable<T>, Sie können etwas auf Null setzen, indem Sie ein Fragezeichen nach dem Typ wie folgt setzen int?.
Es wäre schön, wenn C # so etwas wie die NotNull<T>obige Struktur und eine ähnliche Abkürzung hätte, vielleicht das Ausrufezeichen (!), Damit Sie etwas schreiben könnten wie : public void WriteName(Person! person).
@ JohnSaunders wage ich zu fragen warum? (Ernsthaft aber warum?)
Luis Perez
2
NullReferenceException soll von der CLR ausgelöst werden. Dies bedeutet, dass ein Verweis auf eine Null aufgetreten ist. Dies bedeutet nicht, dass ein Verweis auf eine Null auftreten würde, außer dass Sie dies zuerst sorgfältig überprüft haben.
John Saunders
Ich sehe Ihren Standpunkt dazu, wie verwirrend das wäre. Ich habe es für dieses Beispiel auf eine reguläre Ausnahme und eine benutzerdefinierte Ausnahme in GitHub aktualisiert.
Luis Perez
Gute Antwort auf solch eine grundlegende Frage. Es ist nicht so schlimm, wenn Ihr Code fehlschlägt. Es ist schrecklich, wenn es aus einer kommerziellen Bibliothek eines Drittanbieters kommt, auf die Sie sich verlassen, und der Kundensupport besteht weiterhin darauf, dass es Ihr Code sein muss, der das Problem verursacht. Und Sie sind sich nicht ganz sicher, ob dies nicht der Fall ist, und das gesamte Projekt ist zum Stillstand gekommen. Ich denke tatsächlich, dass dies ein geeignetes Epitaph für meinen Grabstein sein könnte: "Objektreferenz nicht auf eine Instanz eines Objekts festgelegt."
Darrel Lee
10
Interessanterweise erwähnt keine der Antworten auf dieser Seite die beiden Randfälle. Ich hoffe, es macht niemandem etwas aus, wenn ich sie hinzufüge:
Randfall Nr. 1: gleichzeitiger Zugriff auf ein Wörterbuch
Generische Wörterbücher in .NET sind nicht threadsicher und werfen manchmal ein NullReferenceoder sogar (häufiger) einKeyNotFoundException auslösen, wenn Sie versuchen, über zwei gleichzeitige Threads auf einen Schlüssel zuzugreifen. Die Ausnahme ist in diesem Fall ziemlich irreführend.
Randfall Nr. 2: unsicherer Code
Wenn a NullReferenceExceptionvom unsafeCode ausgelöst wird , können Sie sich Ihre Zeigervariablen ansehen und sie überprüfenIntPtr.Zero oder etwas . Das ist dasselbe ("Nullzeiger-Ausnahme"), aber in unsicherem Code werden Variablen häufig in Werttypen / Arrays usw. umgewandelt, und Sie schlagen Ihren Kopf gegen die Wand und fragen sich, wie ein Werttyp dies auslösen kann Ausnahme.
(Ein weiterer Grund für die Nichtverwendung von unsicherem Code, es sei denn, Sie benötigen ihn übrigens)
Ihr Wörterbuchbeispiel ist kein Randfall. Wenn das Objekt nicht threadsicher ist, führt die Verwendung aus mehreren Threads zu zufälligen Ergebnissen. Ihr unsicheres Codebeispiel unterscheidet sich von nullwelcher?
John Saunders
10
Sie können NullReferenceException auf saubere Weise mithilfe von Null-bedingten Operatoren in c # 6 beheben und weniger Code schreiben, um Nullprüfungen durchzuführen.
Es wird verwendet, um auf Null zu testen, bevor eine Mitgliedszugriffs- (?.) Oder Indexoperation (? [) Ausgeführt wird.
Beispiel
var name = p?.Spouse?.FirstName;
ist äquivalent zu:
if(p !=null){if(p.Spouse!=null){
name = p.Spouse.FirstName;}}
Das Ergebnis ist, dass der Name null ist, wenn p null ist oder wenn p.Spouse null ist.
Andernfalls wird dem Variablennamen der Wert von p.Spouse.FirstName zugewiesen.
Die Fehlerzeile "Objektreferenz nicht auf eine Instanz eines Objekts festgelegt" gibt an, dass Sie einer Objektreferenz kein Instanzobjekt zugewiesen haben und dennoch auf Eigenschaften / Methoden dieses Objekts zugreifen.
Beispiel: Angenommen, Sie haben eine Klasse namens myClass, die eine Eigenschaft prop1 enthält.
publicClass myClass
{publicint prop1 {get;set;}}
Jetzt greifen Sie in einer anderen Klasse wie unten auf diese Requisite zu:
publicclassDemo{publicvoid testMethod(){
myClass ref=null;ref.prop1 =1;//This line throws error}}
Die obige Zeile löst einen Fehler aus, weil die Referenz der Klasse myClass deklariert, aber nicht instanziiert ist oder eine Instanz des Objekts nicht der Referenz dieser Klasse zugewiesen ist.
Um dies zu beheben, müssen Sie instanziieren (Objekt der Referenz dieser Klasse zuweisen).
NullReferenceException oder Objektreferenz, die nicht auf eine Instanz eines Objekts festgelegt ist, tritt auf, wenn ein Objekt der Klasse, die Sie verwenden möchten, nicht instanziiert wird. Zum Beispiel:
Wie im obigen Code zu sehen ist, deklariert die Anweisung
Student s - nur die Variable vom Typ Student. Beachten Sie, dass die Student-Klasse zu diesem Zeitpunkt nicht instanziiert wird. Wenn die Anweisung s.GetFullName () ausgeführt wird, wird daher die NullReferenceException ausgelöst.
Sie versuchen, auf ein Objekt zuzugreifen, das nicht erstellt wurde oder sich derzeit nicht im Speicher befindet.
Wie kann man das angehen?
Debuggen und den Debugger brechen lassen ... Sie gelangen direkt zu der defekten Variablen ... Jetzt müssen Sie dies einfach beheben. Verwenden Sie das neue Schlüsselwort an der entsprechenden Stelle.
Wenn dies bei einigen Datenbankbefehlen verursacht wird , weil das Objekt nicht vorhanden ist, müssen Sie lediglich eine Nullprüfung durchführen und damit umgehen:
if(i ==null){// Handle this}
Am schwierigsten ist es, wenn der GC das Objekt bereits erfasst hat. Dies tritt im Allgemeinen auf, wenn Sie versuchen, ein Objekt mithilfe von Zeichenfolgen zu finden. Wenn Sie es also anhand des Objektnamens suchen, kann es vorkommen, dass der GC dies bereits tut bereinigt ... Dies ist schwer zu finden und wird zu einem ziemlichen Problem ... Eine bessere Möglichkeit, dies zu beheben, besteht darin, während des Entwicklungsprozesses erforderlichenfalls Nullprüfungen durchzuführen. So sparen Sie viel Zeit.
Mit Suchen nach Namen meine ich, dass einige Frameworks es Ihnen ermöglichen, FIndObjects mithilfe von Zeichenfolgen zu finden, und der Code könnte folgendermaßen aussehen: FindObject ("ObjectName");
Wenn Sie einen Verweis auf ein Objekt haben, bereinigt der GC es nie
John Saunders
2
Wenn Sie Dinge wie FindObject ("Name des Objekts") verwenden, wird GC auf keinen Fall vorher wissen, dass Sie dieses Objekt referenzieren werden. Dies ist, was versucht wurde zu erklären. Diese treten zur Laufzeit auf
Akash Gutha
2
Es gibt einige Frameworks, die diese Funktionalität in C # bereitstellen, z. B. Unity. Die Frage hat nichts mit BCl zu tun. Durchsuchen Sie das Internet, bevor Sie kritisieren. Es gibt eine Menge solcher Funktionen, und für Ihre Informationen verwende ich sie sogar täglich. Sagen Sie mir jetzt bitte, wie die Antwort keinen Sinn ergibt.
Die Beispiele, die ich in Ihrem Link gesehen habe, weisen die Ergebnisse von GameObject.Find einem Mitgliedsfeld zu. Dies ist eine Referenz, die vom GC erst erfasst wird, wenn das enthaltene Objekt erfasst wurde.
John Saunders
1
Der einfachste Weg, eine NullReferenceExeption zu reparieren, hat buchstäblich zwei Möglichkeiten. Wenn Sie beispielsweise ein GameObject mit einem angehängten Skript und einer Variablen namens rb (Rigidbody) haben, wird diese Variable beim Starten Ihres Spiels mit null gestartet.
Aus diesem Grund erhalten Sie eine NullReferenceExeption, da auf dem Computer keine Daten in dieser Variablen gespeichert sind.
Ich werde eine RigidBody-Variable als Beispiel verwenden.
Wir können Daten wirklich einfach auf verschiedene Arten hinzufügen:
Fügen Sie Ihrem Objekt mit AddComponent> Physik> Rigidbody einen RigidBody hinzu. Gehen Sie
dann in Ihr Skript und geben Sie Folgendes ein. rb = GetComponent<Rigidbody>();
Diese Codezeile funktioniert am besten unter Ihren Start()oder Awake()Funktionen.
Sie können eine Komponente programmgesteuert hinzufügen und die Variable gleichzeitig mit einer Codezeile zuweisen: rb = AddComponent<RigidBody>();
Weitere Hinweise: Wenn Sie möchten, dass Unity Ihrem Objekt eine Komponente hinzufügt, und Sie möglicherweise vergessen haben, eine Komponente hinzuzufügen, können Sie [RequireComponent(typeof(RigidBody))]über Ihrer Klassendeklaration (dem Leerzeichen unter all Ihren Verwendungen) etwas eingeben.
Viel Spaß beim Spielen!
Wenn wir häufige Szenarien betrachten, in denen diese Ausnahme ausgelöst werden kann, greifen Sie auf Eigenschaften mit dem Objekt oben zu.
Ex:
string postalcode=Customer.Address.PostalCode;//if customer or address is null , this will through exeption
Wenn hier die Adresse null ist, erhalten Sie die NullReferenceException.
In der Praxis sollten wir daher immer die Nullprüfung verwenden, bevor wir auf Eigenschaften in solchen Objekten zugreifen (insbesondere bei generischen Objekten).
string postalcode=Customer?.Address?.PostalCode;//if customer or address is null , this will return null, without through a exception
Dies ist im Grunde eine Nullreferenzausnahme . Wie Microsoft feststellt-
Eine NullReferenceException-Ausnahme wird ausgelöst, wenn Sie versuchen, auf ein Mitglied eines Typs zuzugreifen, dessen Wert null ist.
Was bedeutet das?
Das heißt, wenn ein Mitglied, das keinen Wert hat und wir dieses Mitglied dazu bringen, eine bestimmte Aufgabe auszuführen, wird das System zweifellos eine Nachricht werfen und sagen:
"Hey, warte, dieses Mitglied hat keine Werte, also kann es die Aufgabe, die du ihm übergibst, nicht ausführen."
Die Ausnahme selbst besagt, dass etwas verwiesen wird, dessen Wert jedoch nicht festgelegt wird. Dies bedeutet also, dass es nur bei Verwendung von Referenztypen auftritt, da Werttypen nicht nullwertfähig sind.
NullReferenceException tritt nicht auf, wenn Mitglieder vom Typ Wert verwendet werden.
Der obige Code zeigt eine einfache Zeichenfolge, die mit einem Nullwert belegt ist.
Wenn ich jetzt versuche, die Länge der Zeichenfolge str zu drucken , wird eine nicht behandelte Ausnahme vom Typ 'System.NullReferenceException' angezeigt, da Mitglied str auf null zeigt und es keine Länge von null geben kann.
' NullReferenceException ' tritt auch auf, wenn wir vergessen, einen Referenztyp zu instanziieren.
Angenommen, ich habe eine Klassen- und Mitgliedsmethode. Ich habe meine Klasse nicht instanziiert, sondern nur meine Klasse benannt. Wenn ich nun versuche, die Methode zu verwenden, gibt der Compiler einen Fehler aus oder gibt eine Warnung aus (abhängig vom Compiler).
classProgram{staticvoidMain(string[] args){MyClass1 obj;
obj.foo();//Use of unassigned local variable 'obj'}}publicclassMyClass1{internalvoid foo(){Console.WriteLine("hello from foo");}}
Der Compiler für den obigen Code löst einen Fehler aus, dass die Variable obj nicht zugewiesen ist, was bedeutet, dass unsere Variable Nullwerte oder nichts hat. Der Compiler für den obigen Code löst einen Fehler aus, dass die Variable obj nicht zugewiesen ist, was bedeutet, dass unsere Variable Nullwerte oder nichts hat.
Warum tritt es auf?
NullReferenceException entsteht aufgrund unseres Fehlers, den Wert des Objekts nicht zu überprüfen. Wir lassen die Objektwerte in der Codeentwicklung oft unkontrolliert.
Es entsteht auch, wenn wir vergessen, unsere Objekte zu instanziieren. Die Verwendung dieser Methode kann auch die Verwendung von Methoden, Eigenschaften, Sammlungen usw. sein, die Nullwerte zurückgeben oder festlegen können.
Wie kann es vermieden werden?
Es gibt verschiedene Möglichkeiten und Methoden, um diese bekannte Ausnahme zu vermeiden:
Explizite Überprüfung: Wir sollten uns an die Tradition halten, Objekte, Eigenschaften, Methoden, Arrays und Sammlungen zu überprüfen, ob sie null sind. Dies kann einfach mithilfe von bedingten Anweisungen wie if-else if-else usw. implementiert werden.
Ausnahmebehandlung: Eine der wichtigsten Möglichkeiten zur Verwaltung dieser Ausnahme. Mit einfachen Try-Catch-finally-Blöcken können wir diese Ausnahme steuern und auch ein Protokoll darüber führen. Dies kann sehr nützlich sein, wenn sich Ihre Anwendung in der Produktionsphase befindet.
Null-Operatoren: Null-Coalescing-Operatoren und Null-Bedingungsoperatoren können auch nützlich sein, wenn Werte für Objekte, Variablen, Eigenschaften und Felder festgelegt werden.
Debugger: Für Entwickler haben wir die große Waffe des Debuggens dabei. Wenn wir während der Entwicklung mit NullReferenceException konfrontiert sind, können wir den Debugger verwenden, um zur Quelle der Ausnahme zu gelangen.
Eingebaute Methode: Systemmethoden wie GetValueOrDefault (), IsNullOrWhiteSpace () und IsNullorEmpty () suchen nach Nullen und weisen den Standardwert zu, wenn ein Nullwert vorhanden ist.
Hier gibt es bereits viele gute Antworten. Sie können auch eine detailliertere Beschreibung mit Beispielen in meinem Blog überprüfen .
Sie haben im Grunde die Hälfte dieses Blogposts kopiert und nichts Neues hinzugefügt, auf das vorhandene Antworten nicht eingehen.
CodeCaster
@codecaster Wird beim Kopieren einer Zusammenfassung aus Ihrem eigenen Blog das Kopieren angezeigt? Ich weiß, dass meine Antwort nichts Neues enthält und nichts Neues, was frühere Antworten nicht haben, aber ich möchte auf differenziertere Weise dazu beitragen und andere verstehen lassen, wie ich es verstanden habe. Wird froh sein, auch wenn es einer einzelnen Person hilft. In guter Absicht.
Wasim
-4
Wenn diese Meldung beim Speichern oder Kompilieren des Builds angezeigt wird, schließen Sie einfach alle Dateien und öffnen Sie eine beliebige Datei zum Kompilieren und Speichern.
Für mich war der Grund, dass ich die Datei umbenannt hatte und die alte Datei noch offen war.
Antworten:
Was ist die Ursache?
Endeffekt
Sie versuchen, etwas zu verwenden, das
null
(oderNothing
in VB.NET) ist. Dies bedeutet, dass Sie es entweder aufnull
oder gar nichts einstellen.Wie alles andere wird
null
herumgereicht. Wenn esnull
in Verfahren „A“, könnte es diese Methode „B“ sein , eine übergebennull
zu Verfahren „A“.null
kann verschiedene Bedeutungen haben:NullReferenceException
.null
absichtlich, um anzuzeigen, dass kein aussagekräftiger Wert verfügbar ist. Beachten Sie, dass C # das Konzept nullbarer Datentypen für Variablen hat (wie Datenbanktabellen nullfähige Felder haben können) - Sie könnennull
ihnen zuweisen , um anzuzeigen, dass kein Wert darin gespeichert ist, z. B.int? a = null;
wenn das Fragezeichen angibt, dass null gespeichert werden darf variabela
. Sie können dies entweder mitif (a.HasValue) {...}
oder mit überprüfenif (a==null) {...}
. Nullable Variablen, wie ina
diesem Beispiel, ermöglichen dena.Value
expliziten Zugriff auf den Wert über oder wie gewohnt übera
.Beachten Sie, dass es über den Zugriff
a.Value
wirft einenInvalidOperationException
statt eines ,NullReferenceException
wenna
ISnull
- Sie sollten die Prüfung im Voraus durchführen. Wenn Sie also eine andere Variable mit Nullwert haben,int b;
sollten Sie Zuweisungen wieif (a.HasValue) { b = a.Value; }
oder kürzer ausführenif (a != null) { b = a; }
.Der Rest dieses Artikels geht detaillierter und zeigt Fehler, die viele Programmierer häufig machen und die zu a führen können
NullReferenceException
.Genauer
Das
runtime
Werfen eines bedeutetNullReferenceException
immer dasselbe: Sie versuchen, eine Referenz zu verwenden, und die Referenz wird nicht initialisiert (oder sie wurde einmal initialisiert, wird aber nicht mehr initialisiert).Dies bedeutet, dass die Referenz lautet
null
und Sie nicht über einenull
Referenz auf Mitglieder (z. B. Methoden) zugreifen können . Der einfachste Fall:Dies wirft ein a
NullReferenceException
in die zweite Zeile, da Sie die InstanzmethodeToUpper()
für einestring
Referenz, auf die verweist, nicht aufrufen könnennull
.Debuggen
Wie finden Sie die Quelle von a
NullReferenceException
? Abgesehen von der Betrachtung der Ausnahme selbst, die genau an der Stelle ausgelöst wird, an der sie auftritt, gelten die allgemeinen Regeln für das Debuggen in Visual Studio: Platzieren Sie strategische Haltepunkte und überprüfen Sie Ihre Variablen , indem Sie entweder mit der Maus über deren Namen fahren und ein (öffnen) Schnell) Beobachten Sie das Fenster oder verwenden Sie die verschiedenen Debugging-Bereiche wie Locals und Autos.Wenn Sie herausfinden möchten, wo die Referenz festgelegt ist oder nicht, klicken Sie mit der rechten Maustaste auf den Namen und wählen Sie "Alle Referenzen suchen". Sie können dann an jedem gefundenen Speicherort einen Haltepunkt platzieren und Ihr Programm mit dem angehängten Debugger ausführen. Jedes Mal, wenn der Debugger an einem solchen Haltepunkt unterbrochen wird, müssen Sie feststellen, ob die Referenz nicht null sein soll, die Variable überprüfen und sicherstellen, dass sie auf eine Instanz verweist, wenn Sie dies erwarten.
Wenn Sie dem Programmablauf auf diese Weise folgen, können Sie den Speicherort ermitteln, an dem die Instanz nicht null sein sollte und warum sie nicht richtig festgelegt ist.
Beispiele
Einige häufige Szenarien, in denen die Ausnahme ausgelöst werden kann:
Generisch
Wenn ref1 oder ref2 oder ref3 null ist, erhalten Sie eine
NullReferenceException
. Wenn Sie das Problem lösen möchten, finden Sie heraus, welches Null ist, indem Sie den Ausdruck in sein einfacheres Äquivalent umschreiben:Insbesondere in
HttpContext.Current.User.Identity.Name
derHttpContext.Current
könnte null sein, oder dieUser
Eigenschaft null sein könnte, oder dieIdentity
Eigenschaft null sein könnte.Indirekt
Wenn Sie die untergeordnete Nullreferenz (Person) vermeiden möchten, können Sie sie im Konstruktor des übergeordneten (Buch-) Objekts initialisieren.
Initialisierer für verschachtelte Objekte
Gleiches gilt für verschachtelte Objektinitialisierer:
Dies bedeutet
Während das
new
Schlüsselwort verwendet wird, wird nur eine neue Instanz von erstelltBook
, jedoch keine neue Instanz vonPerson
, sodassAuthor
die Eigenschaft weiterhin vorhanden istnull
.Initialisierer für verschachtelte Sammlungen
Die verschachtelte Auflistung
Initializers
verhält sich wie folgt:Dies bedeutet
Das
new Person
erstellt nur eine Instanz vonPerson
, aber dieBooks
Sammlung ist nochnull
. Die Auflistungssyntax erstelltInitializer
keine Auflistung fürp1.Books
, sondern übersetzt nur in diep1.Books.Add(...)
Anweisungen.Array
Array-Elemente
Gezackte Arrays
Sammlung / Liste / Wörterbuch
Bereichsvariable (indirekt / verzögert)
Veranstaltungen
öffentliche Klasse Form1 {Privatkunde Kunde;
}}
Dies kann gelöst werden, indem Sie der Konvention folgen, um Feldern einen Unterstrich voranzustellen:
ASP.NET-Seitenlebenszyklus:
ASP.NET-Sitzungswerte
Leere Ansichtsmodelle für ASP.NET MVC
Wenn die Ausnahme auftritt, wenn auf eine Eigenschaft von
@Model
in verwiesen wirdASP.NET MVC View
, müssen Sie verstehen, dass dieModel
in Ihrer Aktionsmethode festgelegt wird, wenn Siereturn
eine Ansicht erstellen. Wenn Sie ein leeres Modell (oder eine Modelleigenschaft) von Ihrem Controller zurückgeben, tritt die Ausnahme auf, wenn die Ansichten darauf zugreifen:Erstellungsreihenfolge und Ereignisse der WPF-Steuerung
WPF
Steuerelemente werden während des AufrufsInitializeComponent
in der Reihenfolge erstellt, in der sie im visuellen Baum angezeigt werden. BeiNullReferenceException
früh erstellten Steuerelementen mit Ereignishandlern usw. wird ein Wert ausgelöst, beiInitializeComponent
dem spät erstellte Steuerelemente referenziert werden.Beispielsweise :
Hier
comboBox1
wird vorher erstelltlabel1
. WenncomboBox1_SelectionChanged
versucht wird, auf `label1 zu verweisen, wurde es noch nicht erstellt.Eine Änderung der Reihenfolge der Deklarationen in der
XAML
(dh Auflistunglabel1
vorcomboBox1
, Ignorieren von Fragen der Designphilosophie, würde zumindest dasNullReferenceException
hier lösen .Besetzung mit
as
Dies wirft kein,
InvalidCastException
sondern gibt ein zurück,null
wenn die Umwandlung fehlschlägt (und wennsomeObject
es selbst null ist). Also sei dir dessen bewusst.LINQ
FirstOrDefault()
undSingleOrDefault()
Die einfachen Versionen
First()
undSingle()
werfen Ausnahmen, wenn es nichts gibt. Die "OrDefault" -Versionen geben in diesem Fall null zurück. Also sei dir dessen bewusst.für jedes
foreach
wird ausgelöst, wenn Sie versuchen, die Nullsammlung zu iterieren. Wird normalerweise durch unerwartetenull
Ergebnisse von Methoden verursacht, die Sammlungen zurückgeben.Realistischeres Beispiel - Wählen Sie Knoten aus dem XML-Dokument aus. Wird ausgelöst, wenn keine Knoten gefunden werden, aber das anfängliche Debuggen zeigt, dass alle Eigenschaften gültig sind:
Möglichkeiten zu vermeiden
Überprüfen
null
und ignorieren Sie explizit Nullwerte.Wenn Sie erwarten, dass die Referenz manchmal null ist, können Sie dies überprüfen,
null
bevor Sie auf Instanzmitglieder zugreifen:Suchen Sie explizit nach
null
einem Standardwert und geben Sie ihn an.Methodenaufruf, von dem Sie erwarten, dass er eine Instanz zurückgibt
null
, kann zurückgegeben werden , beispielsweise wenn das gesuchte Objekt nicht gefunden werden kann. In diesem Fall können Sie einen Standardwert zurückgeben:Suchen Sie explizit nach
null
Methodenaufrufen und lösen Sie eine benutzerdefinierte Ausnahme aus.Sie können auch eine benutzerdefinierte Ausnahme auslösen, um sie im aufrufenden Code abzufangen:
Verwenden Sie
Debug.Assert
diese Option, wenn ein Wert niemals sein solltenull
, um das Problem früher zu erkennen, als die Ausnahme auftritt.Wenn Sie während der Entwicklung wissen, dass eine Methode möglicherweise zurückkehren kann, aber niemals zurückkehren sollte
null
, können Sie sie verwendenDebug.Assert()
, um so schnell wie möglich zu brechen, wenn sie auftritt:Diese Prüfung endet jedoch nicht in Ihrem Release-Build , sodass sie zur Laufzeit im Release-Modus
NullReferenceException
erneutbook == null
ausgelöst wird.Verwenden Sie diese Option
GetValueOrDefault()
fürnullable
Werttypen, um einen Standardwert anzugeben, wenn dies der Fall istnull
.Verwenden Sie den Null-Koaleszenz-Operator:
??
[C #] oderIf()
[VB].Die Abkürzung zum Bereitstellen eines Standardwerts, wenn a
null
auftritt:Verwenden Sie den Nullbedingungsoperator:
?.
oder?[x]
für Arrays (verfügbar in C # 6 und VB.NET 14):Dies wird manchmal auch als sicherer Navigations- oder Elvis-Operator (nach seiner Form) bezeichnet. Wenn der Ausdruck auf der linken Seite des Operators null ist, wird die rechte Seite nicht ausgewertet und stattdessen null zurückgegeben. Das bedeutet Fälle wie diesen:
Wenn die Person keinen Titel hat, wird eine Ausnahme ausgelöst, da versucht wird,
ToUpper
eine Eigenschaft mit einem Nullwert aufzurufen .In
C# 5
und unten kann dies bewacht werden mit:Jetzt ist die Titelvariable null, anstatt eine Ausnahme auszulösen. C # 6 führt hierfür eine kürzere Syntax ein:
Dies führt dazu, dass die Titelvariable vorhanden ist
null
und der Aufruf vonToUpper
nicht erfolgt, wenn dies der Fallperson.Title
istnull
.Natürlich müssen Sie immer noch nach
title
null suchen oder den Nullbedingungsoperator zusammen mit dem Null-Koaleszenzoperator (??
) verwenden, um einen Standardwert anzugeben:Ebenso können Sie für Arrays
?[i]
Folgendes verwenden:Dies führt Folgendes aus: Wenn
myIntArray
null ist, gibt der Ausdruck null zurück und Sie können ihn sicher überprüfen. Wenn es ein Array enthält, funktioniert es wie folgt:elem = myIntArray[i];
und gibt dasi<sup>th</sup>
Element zurück.Verwenden Sie den Nullkontext (verfügbar in C # 8):
Die dort eingeführten
C# 8
Nullkontexte und nullbaren Referenztypen führen eine statische Analyse von Variablen durch und geben eine Compilerwarnung aus, wenn ein Wert möglicherweise null sein kann oder auf null gesetzt wurde. Mit den nullbaren Referenztypen können Typen explizit null sein.Der annullierbare Annotationskontext und der nullbare Warnkontext können für ein Projekt mithilfe des
Nullable
Elements in Ihrercsproj
Datei festgelegt werden. Dieses Element konfiguriert, wie der Compiler die Nullfähigkeit von Typen interpretiert und welche Warnungen generiert werden. Gültige Einstellungen sind:Ein nullbarer Referenztyp wird mit derselben Syntax wie nullbare Werttypen notiert: a
?
wird an den Typ der Variablen angehängt.Spezielle Techniken zum Debuggen und Beheben von Null-Derefs in Iteratoren
C#
unterstützt "Iteratorblöcke" (in einigen anderen gängigen Sprachen "Generatoren" genannt). Null-Dereferenzierungsausnahmen können aufgrund der verzögerten Ausführung in Iteratorblöcken besonders schwierig zu debuggen sein:Wenn
whatever
Ergebnisse innull
dannMakeFrob
wird werfen. Nun könnte man denken, dass das Richtige das Folgende ist:Warum ist das falsch? Da der Iteratorblock eigentlich nicht laufen , bis die
foreach
! Der Aufruf,GetFrobs
einfach ein Objekt zurückzugeben, das bei Iteration den Iteratorblock ausführt.Wenn Sie eine Nullprüfung wie diese schreiben, verhindern Sie die Null-Dereferenzierung, aber Sie verschieben die Nullargument-Ausnahme an den Punkt der Iteration , nicht an den Punkt des Aufrufs , und das Debuggen ist sehr verwirrend .
Die richtige Lösung ist:
Erstellen Sie also eine private Hilfsmethode mit der Iteratorblocklogik und eine öffentliche Oberflächenmethode, die die Nullprüfung durchführt und den Iterator zurückgibt. Wenn jetzt
GetFrobs
aufgerufen wird, erfolgt die Nullprüfung sofort und wird dannGetFrobsForReal
ausgeführt, wenn die Sequenz wiederholt wird.Wenn Sie die Referenzquelle für
LINQ
Objekte untersuchen, werden Sie feststellen, dass diese Technik durchgehend verwendet wird. Das Schreiben ist etwas umständlicher, erleichtert jedoch das Debuggen von Nullitätsfehlern erheblich. Optimieren Sie Ihren Code für die Bequemlichkeit des Anrufers und nicht für die Bequemlichkeit des Autors .Ein Hinweis zu Null-Dereferenzen in unsicherem Code
C#
hat einen "unsicheren" Modus, der, wie der Name schon sagt, äußerst gefährlich ist, da die normalen Sicherheitsmechanismen, die Speichersicherheit und Typensicherheit bieten, nicht durchgesetzt werden. Sie sollten keinen unsicheren Code schreiben, es sei denn, Sie haben ein gründliches und tiefes Verständnis der Funktionsweise des Speichers .Im unsicheren Modus sollten Sie zwei wichtige Fakten kennen:
Um zu verstehen, warum das so ist, ist es hilfreich zu verstehen, wie .NET überhaupt Null-Dereferenzierungsausnahmen erzeugt. (Diese Angaben gelten für .NET unter Windows. Andere Betriebssysteme verwenden ähnliche Mechanismen.)
Speicher wird in virtualisiert
Windows
; Jeder Prozess erhält einen virtuellen Speicherplatz mit vielen "Seiten" Speicher, die vom Betriebssystem verfolgt werden. Auf jeder Speicherseite sind Flags gesetzt, die bestimmen, wie sie verwendet werden dürfen: Lesen, Schreiben, Ausführen usw. Die unterste Seite ist als "Fehler erzeugen, wenn sie jemals in irgendeiner Weise verwendet wurde" markiert.Sowohl ein Nullzeiger als auch eine Nullreferenz in
C#
werden intern als die Zahl Null dargestellt. Daher führt jeder Versuch, sie in den entsprechenden Speicher zu dereferenzieren, dazu, dass das Betriebssystem einen Fehler erzeugt. Die .NET-Laufzeit erkennt diesen Fehler und verwandelt ihn in die Null-Dereferenzierungsausnahme.Aus diesem Grund führt die Dereferenzierung sowohl eines Nullzeigers als auch einer Nullreferenz zu derselben Ausnahme.
Was ist mit dem zweiten Punkt? Das Dereferenzieren eines ungültigen Zeigers, der auf die unterste Seite des virtuellen Speichers fällt, verursacht denselben Betriebssystemfehler und damit dieselbe Ausnahme.
Warum macht das Sinn? Angenommen, wir haben eine Struktur mit zwei Ints und einen nicht verwalteten Zeiger gleich null. Wenn wir versuchen, das zweite int in der Struktur zu dereferenzieren,
CLR
wird nicht versucht, auf den Speicher an Position Null zuzugreifen. Es wird auf den Speicher an Position vier zugreifen. Aber logischerweise ist dies eine Null-Dereferenzierung, da wir über die Null zu dieser Adresse gelangen .Wenn Sie mit unsicherem Code arbeiten und eine Null-Dereferenzierungsausnahme erhalten, beachten Sie nur, dass der fehlerhafte Zeiger nicht null sein muss. Es kann sich um eine beliebige Stelle auf der untersten Seite handeln, und diese Ausnahme wird erzeugt.
quelle
new Book { Author = { Age = 45 } };
Wie funktioniert die innere Initialisierung überhaupt ... Ich kann mir keine Situation vorstellen, in der die innere Initialisierung jemals funktionieren würde, aber sie kompiliert und Intellisense funktioniert ... Es sei denn für Strukturen?NullReference-Ausnahme - Visual Basic
Das
NullReference Exception
für Visual Basic unterscheidet sich nicht von dem in C # . Schließlich melden beide dieselbe Ausnahme, die in .NET Framework definiert ist, das sie beide verwenden. Ursachen, die nur für Visual Basic gelten, sind selten (möglicherweise nur eine).Diese Antwort verwendet Visual Basic-Begriffe, -Syntax und -Kontext. Die verwendeten Beispiele stammen aus einer großen Anzahl früherer Fragen zum Stapelüberlauf. Dies ist Relevanz zu maximieren , indem die Verwendung von Arten von Situationen oft in Beiträgen gesehen. Ein bisschen mehr Erklärung wird auch für diejenigen gegeben, die es brauchen könnten. Ein ähnliches Beispiel wie Ihr ist hier sehr wahrscheinlich aufgeführt.
Hinweis:
NullReferenceException
(NRE) verursacht, wie man es findet, wie man es behebt und wie man es vermeidet. Ein NRE kann auf viele Arten verursacht werden, daher ist es unwahrscheinlich, dass dies Ihre einzige Begegnung ist.Grundlegende Bedeutung
Die Meldung "Objekt nicht auf eine Instanz von Objekt festgelegt" bedeutet, dass Sie versuchen, ein Objekt zu verwenden, das nicht initialisiert wurde. Dies läuft auf eines davon hinaus:
Die Ursache finden
Da das Problem eine Objektreferenz ist
Nothing
, besteht die Antwort darin, sie zu untersuchen, um herauszufinden, welche. Stellen Sie dann fest, warum es nicht initialisiert wurde. Halten Sie die Maus über die verschiedenen Variablen und Visual Studio (VS) zeigt ihre Werte an - der Schuldige istNothing
.Sie sollten auch alle Try / Catch-Blöcke aus dem entsprechenden Code entfernen, insbesondere solche, bei denen der Catch-Block nichts enthält. Dies führt dazu, dass Ihr Code abstürzt, wenn er versucht, ein Objekt zu verwenden
Nothing
. Dies ist das, was Sie möchten, da es den genauen Ort des Problems identifiziert und es Ihnen ermöglicht, das Objekt zu identifizieren, das es verursacht.Ein
MsgBox
angezeigter CatchError while...
hilft wenig. Diese Methode führt auch zu sehr schlechten Fragen zum Stapelüberlauf, da Sie die tatsächliche Ausnahme, das betroffene Objekt oder sogar die Codezeile, in der sie auftritt, nicht beschreiben können.Sie können Ihre Objekte auch mit
Locals Window
( Debug -> Windows -> Locals ) untersuchen.Sobald Sie wissen, was und wo das Problem liegt, ist es normalerweise recht einfach zu beheben und schneller als das Posten einer neuen Frage.
Siehe auch:
Beispiele und Abhilfemaßnahmen
Klassenobjekte / Erstellen einer Instanz
Das Problem ist, dass
Dim
kein CashRegister- Objekt erstellt wird . Es wird nur eine Variable mit diesem Namen deklariertreg
. Das Deklarieren einer Objektvariablen und das Erstellen einer Instanz sind zwei verschiedene Dinge.Abhilfe
Der
New
Operator kann häufig verwendet werden, um die Instanz zu erstellen, wenn Sie sie deklarieren:Wenn es nur angebracht ist, die Instanz später zu erstellen:
Hinweis: Sie nicht verwenden ,
Dim
wieder in einem Verfahren, einschließlich dem Konstruktor (Sub New
):Dadurch wird eine lokale Variable erstellt,
reg
die nur in diesem Kontext (Sub) vorhanden ist. Diereg
Variable mit Modulebene,Scope
die Sie überall sonst verwenden, bleibt erhaltenNothing
.Um klar zu sein, deklariert
Dim
(oderPrivate
) nur eine Variable und ihre . Der Umfang der Variablen - ob sie für das gesamte Modul / die gesamte Klasse vorhanden ist oder für eine Prozedur lokal ist - wird dadurch bestimmt, wo sie deklariert wird. Definiert die Zugriffsebene, nicht den Bereich .Type
Private | Friend | Public
Weitere Informationen finden Sie unter:
Arrays
Arrays müssen auch instanziiert werden:
Dieses Array wurde nur deklariert, nicht erstellt. Es gibt verschiedene Möglichkeiten, ein Array zu initialisieren:
Hinweis: Ab VS 2010 sind beim Initialisieren eines lokalen Arrays mit einem Literal und
Option Infer
die ElementeAs <Type>
undNew
optional:Der Datentyp und die Arraygröße werden aus den zugewiesenen Daten abgeleitet. Klasse / Modulebene Erklärungen erfordern nach wie vor
As <Type>
mitOption Strict
:Beispiel: Array von Klassenobjekten
Das Array wurde erstellt, die darin enthaltenen
Foo
Objekte jedoch nicht.Abhilfe
Die Verwendung eines
List(Of T)
Testaments macht es ziemlich schwierig, ein Element ohne ein gültiges Objekt zu haben:Weitere Informationen finden Sie unter:
Listen und Sammlungen
.NET-Sammlungen (von denen es viele Varianten gibt - Listen, Wörterbuch usw.) müssen ebenfalls instanziiert oder erstellt werden.
Sie erhalten dieselbe Ausnahme aus demselben Grund -
myList
wurde nur deklariert, aber keine Instanz erstellt. Das Mittel ist das gleiche:Ein häufiges Versehen ist eine Klasse, die eine Sammlung verwendet
Type
:Jede Prozedur führt zu einer NRE, da sie
barList
nur deklariert und nicht instanziiert wird. Durch das Erstellen einer Instanz vonFoo
wird nicht auch eine Instanz des internen erstelltbarList
. Möglicherweise war dies die Absicht, dies im Konstruktor zu tun:Dies ist nach wie vor falsch:
Weitere Informationen finden Sie unter
List(Of T)
Klasse .Datenanbieterobjekte
Arbeiten mit Datenbanken bieten viele Möglichkeiten für einen Nullreference , weil es viele Objekte (sein
Command
,Connection
,Transaction
,Dataset
,DataTable
,DataRows
auf einmal ....) im Einsatz. Hinweis: Es spielt keine Rolle, welchen Datenprovider Sie verwenden - MySQL, SQL Server, OleDB usw. - die Konzepte sind dieselben.Beispiel 1
Nach wie vor wurde das
ds
Dataset-Objekt deklariert, es wurde jedoch nie eine Instanz erstellt. DasDataAdapter
wird ein vorhandenes füllenDataSet
, kein erstellt. In diesem Fall warnt Sie die IDE , da diesds
eine lokale Variable ist : Dies könnte passieren:Wenn
con
der Compiler als Variable auf Modul- / Klassenebene deklariert wird, wie dies der Fall zu sein scheint, kann er nicht wissen, ob das Objekt durch eine vorgelagerte Prozedur erstellt wurde. Warnungen nicht ignorieren.Abhilfe
Beispiel 2
Ein Tippfehler ein Problem hier:
Employees
vsEmployee
. Es wurde keinDataTable
Name "Mitarbeiter" erstellt, daher wurde einNullReferenceException
Ergebnis erzielt, bei dem versucht wurde, darauf zuzugreifen. Ein weiteres potenzielles Problem ist die Annahme, dass diesItems
der Fall sein wird, wenn SQL eine WHERE-Klausel enthält.Abhilfe
Da hierfür eine Tabelle verwendet
Tables(0)
wird , werden durch die Verwendung Rechtschreibfehler vermieden. UntersuchenRows.Count
kann auch helfen:Fill
ist eine Funktion, die die Anzahl derRows
Betroffenen zurückgibt, die auch getestet werden kann:Beispiel 3
Das
DataAdapter
wirdTableNames
wie im vorherigen Beispiel gezeigt bereitgestellt, analysiert jedoch keine Namen aus der SQL- oder Datenbanktabelle. Als Ergebnisds.Tables("TICKET_RESERVATION")
verweist auf eine nicht vorhandene Tabelle.Das Mittel ist das gleiche, referenzieren Sie die Tabelle nach Index:
Siehe auch DataTable-Klasse .
Objektpfade / Verschachtelt
Der Code wird nur getestet,
Items
während beidemyFoo
undBar
möglicherweise auch nichts sind. Das Mittel besteht darin, die gesamte Kette oder den gesamten Pfad von Objekten einzeln zu testen:AndAlso
ist wichtig. Nachfolgende Tests werden nicht durchgeführt, sobald die ersteFalse
Bedingung erfüllt ist. Auf diese Weise kann der Code sicher eine Ebene nach der anderen in das Objekt (die Objekte) "bohren"myFoo.Bar
und erst dann auswerten, wenn (und wenn)myFoo
festgestellt wurde, dass es gültig ist. Objektketten oder -pfade können beim Codieren komplexer Objekte sehr lang werden:Es ist nicht möglich, irgendetwas 'stromabwärts' eines
null
Objekts zu referenzieren . Dies gilt auch für Kontrollen:Hier
myWebBrowser
oderDocument
könnte nichts sein oder dasformfld1
Element kann nicht existieren.UI-Steuerelemente
Dieser Code geht unter anderem nicht davon aus, dass der Benutzer möglicherweise etwas in einem oder mehreren UI-Steuerelementen nicht ausgewählt hat.
ListBox1.SelectedItem
kann gut seinNothing
, soListBox1.SelectedItem.ToString
wird in einem NRE führen.Abhilfe
Überprüfen Sie die Daten, bevor Sie sie verwenden (verwenden Sie auch
Option Strict
und SQL-Parameter):Alternativ können Sie verwenden
(ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Visual Basic Forms
Dies ist ein ziemlich üblicher Weg, um ein NRE zu erhalten. In C # meldet die IDE abhängig davon, wie sie codiert ist, dass
Controls
sie im aktuellen Kontext nicht vorhanden ist oder "nicht auf ein nicht statisches Mitglied verweisen kann". Bis zu einem gewissen Grad handelt es sich also nur um eine VB-Situation. Es ist auch komplex, weil es zu einer Ausfallkaskade führen kann.Die Arrays und Sammlungen können auf diese Weise nicht initialisiert werden. Dieser Initialisierungscode wird ausgeführt, bevor der Konstruktor das
Form
oder das erstelltControls
. Als Ergebnis:somevar
Zuweisung führt zu einer sofortigen NRE, da Nothing keine.Text
Eigenschaft hatWenn Sie später auf Array-Elemente verweisen, erhalten Sie eine NRE. Wenn Sie dies
Form_Load
aufgrund eines seltsamen Fehlers tun , meldet die IDE die Ausnahme möglicherweise nicht , wenn sie auftritt. Die Ausnahme wird später angezeigt, wenn Ihr Code versucht, das Array zu verwenden. Diese "stille Ausnahme" wird in diesem Beitrag detailliert beschrieben . Für unsere Zwecke ist der Schlüssel, dass, wenn beim Erstellen eines Formulars (Sub New
oderForm Load
Ereignisses) etwas Katastrophales passiert , Ausnahmen möglicherweise nicht gemeldet werden, der Code die Prozedur beendet und nur das Formular anzeigt.Da kein anderer Code in Ihrem
Sub New
oderForm Load
Ereignis nach dem NRE ausgeführt wird, können viele andere Dinge nicht initialisiert werden.Beachten Sie, dass dies für alle Steuerungs- und Komponentenreferenzen gilt, die diese illegal machen, wo sie sind:
Teilweise Abhilfe
Es ist merkwürdig , dass VB keine Warnung liefern, aber die Lösung ist zu erklären , die Behälter auf Formularebene, sondern initialisieren sie in Form Load - Ereignishandler , wenn die Kontrollen nicht existieren. Dies kann erfolgen,
Sub New
solange sich Ihr Code nach demInitializeComponent
Aufruf befindet:Der Array-Code ist möglicherweise noch nicht aus dem Wald. Alle Steuerelemente, die sich in einem Containersteuerelement befinden (wie ein
GroupBox
oderPanel
), werden nicht in gefundenMe.Controls
. Sie befinden sich in der Controls-Auflistung dieses Panels oder dieser GroupBox. Ein Steuerelement wird auch nicht zurückgegeben, wenn der Steuerelementname falsch geschrieben ist ("TeStBox2"
). In solchen FällenNothing
wird erneut in diesen Array-Elementen gespeichert und es entsteht eine NRE, wenn Sie versuchen, darauf zu verweisen.Diese sollten jetzt leicht zu finden sein, da Sie wissen, wonach Sie suchen:
"Button2" befindet sich auf a
Panel
Abhilfe
Verwenden Sie anstelle indirekter namentlicher Verweise in der Formularsammlung
Controls
die Steuerelementreferenz:Funktion, die nichts zurückgibt
Dies ist ein Fall, in dem die IDE Sie warnt, dass nicht alle Pfade einen Wert zurückgeben und
NullReferenceException
möglicherweise ein Ergebnis resultiert . Sie können die Warnung unterdrücken durch ErsetzenExit Function
mitReturn Nothing
, aber das löst nicht das Problem. Alles, was versucht, die Rückgabe zu verwenden,someCondition = False
führt zu einem NRE:Abhilfe
Ersetzen Sie
Exit Function
in der Funktion durchReturn bList
. Das Zurückgeben eines LeerzeichensList
ist nicht dasselbe wie das ZurückgebenNothing
. Wenn die Möglichkeit besteht, dass ein zurückgegebenes Objekt vorhanden istNothing
, testen Sie es , bevor Sie es verwenden:Try / Catch schlecht implementiert
Ein schlecht implementierter Try / Catch kann verbergen, wo das Problem liegt, und zu neuen führen:
Dies ist ein Fall, in dem ein Objekt nicht wie erwartet erstellt wird, sondern auch die Gegennutzen eines leeren Objekts demonstriert
Catch
.Es gibt ein zusätzliches Komma in der SQL (nach 'Mailadresse'), was zu einer Ausnahme bei führt
.ExecuteReader
. Nachdem derCatch
nichts tut,Finally
versucht er eine Bereinigung durchzuführen, aber da Sie keinClose
Nullobjekt könnenDataReader
,NullReferenceException
ergibt sich ein brandneues Ergebnis.Ein leerer
Catch
Block ist der Spielplatz des Teufels. Dieser OP war verblüfft, warum er eine NRE imFinally
Block bekam. In anderen Situationen kann ein LeerlaufCatch
dazu führen, dass etwas anderes viel weiter stromabwärts durcheinander gerät und Sie Zeit damit verbringen, die falschen Dinge am falschen Ort für das Problem zu suchen. (Die oben beschriebene "stille Ausnahme" bietet den gleichen Unterhaltungswert.)Abhilfe
Verwenden Sie keine leeren Try / Catch-Blöcke - lassen Sie den Code abstürzen, damit Sie a) die Ursache identifizieren, b) den Ort identifizieren und c) ein geeignetes Mittel anwenden können. Try / Catch-Blöcke sollen keine Ausnahmen vor der Person verbergen, die für die Behebung dieser Probleme eindeutig qualifiziert ist - dem Entwickler.
DBNull ist nicht dasselbe wie Nothing
Die
IsDBNull
Funktion wird verwendet, um zu testen, ob ein Wert gleich istSystem.DBNull
: Von MSDN:Abhilfe
Nach wie vor können Sie auf Nothing und dann auf einen bestimmten Wert testen:
Beispiel 2
FirstOrDefault
Gibt das erste Element oder den Standardwert zurück, derNothing
für Referenztypen gilt und niemalsDBNull
:Kontrollen
Wenn ein
CheckBox
withchkName
nicht gefunden werden kann (oder in a vorhanden istGroupBox
),chk
ist Nothing und der Versuch, auf eine Eigenschaft zu verweisen, führt zu einer Ausnahme.Abhilfe
Die DataGridView
Die DGV hat einige Macken, die regelmäßig gesehen werden:
Wenn dies der Fall
dgvBooks
istAutoGenerateColumns = True
, werden die Spalten erstellt, aber nicht benannt, sodass der obige Code fehlschlägt, wenn er nach Namen referenziert wird.Abhilfe
Benennen Sie die Spalten manuell oder referenzieren Sie sie nach Index:
Beispiel 2 - Vorsicht vor der NewRow
Wenn Sie
DataGridView
hatAllowUserToAddRows
alsTrue
(Standardeinstellung), dieCells
in dem Rohling / neue Zeile am unteren Rande wird alle enthaltenNothing
. Die meisten Versuche, den Inhalt zu verwenden (zum BeispielToString
), führen zu einer NRE.Abhilfe
Verwenden Sie eine
For/Each
Schleife und testen Sie dieIsNewRow
Eigenschaft, um festzustellen, ob es sich um die letzte Zeile handelt. Dies funktioniert unabhängig davon, obAllowUserToAddRows
es wahr ist oder nicht:Wenn Sie eine
For n
Schleife verwenden, ändern Sie die Zeilenanzahl oder verwenden Sie,Exit For
wennIsNewRow
true ist.My.Settings (StringCollection)
Unter bestimmten Umständen kann der Versuch, ein Element zu verwenden, von
My.Settings
demStringCollection
a stammt, bei der ersten Verwendung zu einer NullReferenz führen. Die Lösung ist dieselbe, aber nicht so offensichtlich. Erwägen:Da VB die Einstellungen für Sie verwaltet, ist zu erwarten, dass die Sammlung initialisiert wird. Dies ist jedoch nur möglich, wenn Sie zuvor einen ersten Eintrag zur Sammlung hinzugefügt haben (im Einstellungseditor). Da die Sammlung (anscheinend) beim Hinzufügen eines Elements initialisiert wird, bleibt sie erhalten
Nothing
wenn im Einstellungseditor keine Elemente zum Hinzufügen vorhanden sind.Abhilfe
Initialisieren Sie die Einstellungssammlung im
Load
Ereignishandler des Formulars , falls erforderlich.In der Regel muss die
Settings
Sammlung nur beim ersten Ausführen der Anwendung initialisiert werden. Eine alternative Abhilfe besteht darin, Ihrer Sammlung unter Projekt -> Einstellungen | einen Anfangswert hinzuzufügen FooBars , speichern Sie das Projekt und entfernen Sie den gefälschten Wert.Wichtige Punkte
Sie haben wahrscheinlich den
New
Operator vergessen .oder
Etwas, von dem Sie angenommen haben, dass es fehlerfrei funktioniert, um ein initialisiertes Objekt an Ihren Code zurückzugeben, hat dies nicht getan.
Ignorieren Sie Compiler-Warnungen nicht (jemals) und verwenden Sie sie
Option Strict On
(immer).MSDN NullReference-Ausnahme
quelle
Ein anderes Szenario ist, wenn Sie ein Nullobjekt in einen Werttyp umwandeln . Zum Beispiel der folgende Code:
Es wird einen
NullReferenceException
auf die Besetzung werfen. Im obigen Beispiel scheint dies ziemlich offensichtlich zu sein, aber dies kann in komplizierteren Szenarien geschehen, in denen das Nullobjekt von einem Code zurückgegeben wurde, den Sie nicht besitzen, und die Umwandlung beispielsweise von einem automatischen System generiert wird.Ein Beispiel hierfür ist dieses einfache ASP.NET-Bindungsfragment mit dem Kalendersteuerelement:
Hier
SelectedDate
handelt es sich tatsächlich um eine Eigenschaft - vomDateTime
Typ - vom TypCalendar
Web Control, und die Bindung könnte perfekt etwas Null zurückgeben. Der implizite ASP.NET-Generator erstellt einen Code, der dem obigen Cast-Code entspricht. Und dies führt zu einem ProblemNullReferenceException
, das ziemlich schwer zu erkennen ist, da es in von ASP.NET generiertem Code liegt, der sich gut kompilieren lässt ...quelle
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Dies bedeutet, dass die betreffende Variable auf nichts zeigt. Ich könnte das so erzeugen:
Das wird den Fehler auslösen, denn während ich die Variable "
connection
" deklariert habe , zeigt sie auf nichts. Wenn ich versuche, das Mitglied "Open
" aufzurufen , gibt es keinen Verweis, den es lösen könnte, und es wird den Fehler auslösen.So vermeiden Sie diesen Fehler:
object == null
.Das Resharper-Tool von JetBrains identifiziert jede Stelle in Ihrem Code, an der möglicherweise ein Nullreferenzfehler auftritt, sodass Sie eine Nullprüfung durchführen können. Dieser Fehler ist meiner Meinung nach die häufigste Fehlerquelle.
quelle
Dies bedeutet, dass Ihr Code eine Objektreferenzvariable verwendet hat, die auf null gesetzt wurde (dh keine tatsächliche Objektinstanz referenziert hat).
Um den Fehler zu vermeiden, sollten Objekte, die null sein könnten, vor der Verwendung auf null getestet werden.
quelle
Beachten Sie, dass die Ursache in .NET unabhängig vom Szenario immer dieselbe ist:
quelle
Ein Beispiel für diese Ausnahme ist: Wenn Sie versuchen, etwas zu überprüfen, ist dies null.
Zum Beispiel:
Die .NET-Laufzeit löst eine NullReferenceException aus, wenn Sie versuchen, eine Aktion für etwas auszuführen, das nicht instanziiert wurde, z. B. den obigen Code.
Im Vergleich zu einer ArgumentNullException, die normalerweise als Abwehrmaßnahme ausgelöst wird, wenn eine Methode erwartet, dass das, was an sie übergeben wird, nicht null ist.
Weitere Informationen finden Sie in C # NullReferenceException und Null Parameter .
quelle
Update C # 8.0, 2019: Nullable Referenztypen
C # 8.0 führt nullbare Referenztypen und nicht nullbare Referenztypen ein . Daher müssen nur nullfähige Referenztypen überprüft werden, um eine NullReferenceException zu vermeiden .
Wenn Sie keinen Referenztyp initialisiert haben und eine seiner Eigenschaften festlegen oder lesen möchten, wird eine NullReferenceException ausgelöst .
Beispiel:
Sie können dies einfach vermeiden, indem Sie überprüfen, ob die Variable nicht null ist:
Um vollständig zu verstehen , warum ein Nullreferenceexception geworfen wird, ist es wichtig , den Unterschied zwischen wissen , Werttypen und [Referenztypen] [3].
Also, wenn Sie es zu tun Werttypen können NullReferenceExceptions nicht auftreten. Allerdings müssen Sie beim Umgang mit Referenztypen wachsam sein !
Nur Referenztypen können, wie der Name schon sagt, Referenzen enthalten oder buchstäblich auf nichts (oder 'null') verweisen. Während Werttypen immer einen Wert enthalten.
Referenztypen (diese müssen überprüft werden):
Werttypen (Sie können diese einfach ignorieren):
quelle
Ein weiterer Fall, in dem
NullReferenceExceptions
dies passieren kann, ist die (falsche) Verwendung desas
Operators :Hier
Book
undCar
sind inkompatible Typen; aCar
kann nicht konvertiert / in a umgewandelt werdenBook
. Wenn diese Besetzung fehlschlägt,as
kehrt sie zurücknull
. Die Verwendungmybook
danach bewirkt aNullReferenceException
.Im Allgemeinen sollten Sie eine Besetzung verwenden oder
as
wie folgt:Wenn Sie erwarten, dass die Typkonvertierung immer erfolgreich ist (dh Sie wissen, was das Objekt im Voraus sein sollte), sollten Sie eine Umwandlung verwenden:
Wenn Sie sich über den Typ nicht sicher sind, aber versuchen möchten, ihn als bestimmten Typ zu verwenden, verwenden Sie
as
:quelle
Sie verwenden das Objekt, das die Nullwertreferenz enthält. Es gibt also eine Null-Ausnahme. Im Beispiel ist der Zeichenfolgenwert null, und bei der Überprüfung seiner Länge ist die Ausnahme aufgetreten.
Beispiel:
Der Ausnahmefehler ist:
quelle
Während die Ursachen für NullReferenceExceptions und Ansätze zur Vermeidung / Behebung einer solchen Ausnahme in anderen Antworten behandelt wurden, haben viele Programmierer noch nicht gelernt, wie solche Ausnahmen während der Entwicklung unabhängig voneinander debuggt werden können.
In Visual Studio ist dies dank des Visual Studio-Debuggers normalerweise einfach .
Stellen Sie zunächst sicher, dass der richtige Fehler abgefangen wird - siehe Wie erlaube ich das Unterbrechen von 'System.NullReferenceException' in VS2010? Anmerkung 1
Beginnen Sie dann entweder mit dem Debuggen (F5) oder hängen Sie [den VS-Debugger] an den laufenden Prozess an . Gelegentlich kann die Verwendung hilfreich sein
Debugger.Break
, um den Debugger zu starten.Wenn nun die NullReferenceException ausgelöst (oder nicht behandelt) wird, stoppt der Debugger in der Zeile, in der die Ausnahme aufgetreten ist (erinnern Sie sich an den oben festgelegten Regelsatz?). Manchmal ist der Fehler leicht zu erkennen.
In der folgenden Zeile ist der einzige Code, der die Ausnahme verursachen kann, der
myString
Wert null. Dies kann überprüft werden, indem Sie das Überwachungsfenster betrachten oder Ausdrücke im Direktfenster ausführen .In fortgeschritteneren Fällen, wie den folgenden, müssen Sie eine der oben genannten Techniken (Watch oder Immediate Windows) verwenden, um die Ausdrücke zu überprüfen, um festzustellen, ob
str1
null oderstr2
null waren.Einmal wo die Ausnahme throw ist lokalisiert worden, es Grund rückwärts in der Regel trivial ist, um herauszufinden , wo der Nullwert [falsch] eingeführt wurde -
Nehmen Sie sich Zeit, um die Ursache der Ausnahme zu verstehen. Auf Nullausdrücke prüfen. Überprüfen Sie die vorherigen Ausdrücke, die zu solchen Nullausdrücken hätten führen können. Fügen Sie Haltepunkte hinzu und führen Sie das Programm entsprechend durch.Verwenden Sie den Debugger.
1 Wenn Break on Throws zu aggressiv ist und der Debugger auf einer NPE in der .NET- oder Drittanbieter-Bibliothek stoppt, kann Break on User-Unhandled verwendet werden, um die abgefangenen Ausnahmen zu begrenzen. Darüber hinaus führt VS2012 Just My Code ein, das ich ebenfalls aktivieren möchte .
quelle
Simon Mourier gab dieses Beispiel :
wobei eine Unboxing- Konvertierung (Umwandlung) von
object
(oder von einer der KlassenSystem.ValueType
oder oderSystem.Enum
oder von einem Schnittstellentyp) in einen Werttyp (außerNullable<>
) an sich das ergibtNullReferenceException
.In der anderen Richtung wird eine boxing Umwandlung von a
Nullable<>
welchesHasValue
gleichfalse
zu einem Referenz - Typ kann eine gebennull
Referenz , die auf ein später führen kannNullReferenceException
. Das klassische Beispiel ist:Manchmal geschieht das Boxen auf andere Weise. Zum Beispiel mit dieser nicht generischen Erweiterungsmethode:
Der folgende Code ist problematisch:
Diese Fälle entstehen aufgrund der speziellen Regeln, die die Laufzeit beim Boxen von
Nullable<>
Instanzen verwendet.quelle
Hinzufügen eines Falls, in dem der Klassenname für die im Entitätsframework verwendete Entität mit dem Klassennamen für eine Webformular-CodeBehind-Datei identisch ist.
Angenommen, Sie haben ein Webformular Contact.aspx, dessen Codebehind-Klasse Contact ist, und Sie haben einen Entitätsnamen Contact.
Der folgende Code löst dann eine NullReferenceException aus, wenn Sie context.SaveChanges () aufrufen.
Der Vollständigkeit halber DataContext-Klasse
und Kontaktentitätsklasse. Manchmal sind Entitätsklassen Teilklassen, sodass Sie sie auch in anderen Dateien erweitern können.
Der Fehler tritt auf, wenn sich sowohl die Entität als auch die Codebehind-Klasse im selben Namespace befinden. Um dies zu beheben, benennen Sie die Entitätsklasse oder die Codebehind-Klasse für Contact.aspx um.
Grund Ich bin mir immer noch nicht sicher über den Grund. Aber wenn eine der Entitätsklassen System.Web.UI.Page erweitert, tritt dieser Fehler auf.
Zur Diskussion werfen Sie einen Blick auf NullReferenceException in DbContext.saveChanges ()
quelle
Ein weiterer allgemeiner Fall, in dem diese Ausnahme auftreten kann, besteht darin, Klassen während des Komponententests zu verspotten. Unabhängig vom verwendeten Verspottungsframework müssen Sie sicherstellen, dass alle geeigneten Ebenen der Klassenhierarchie ordnungsgemäß verspottet sind. Insbesondere alle Eigenschaften von
HttpContext
verspottet werden, auf die der zu testende Code verweist.Ein etwas ausführliches Beispiel finden Sie unter " NullReferenceException beim Testen eines benutzerdefinierten AuthorizationAttribute ".
quelle
Ich habe eine andere Perspektive als darauf zu antworten. Diese Art von Antworten "Was kann ich noch tun, um dies zu vermeiden? "
Wenn ein Controller über verschiedene Ebenen hinweg arbeitet , beispielsweise in einer MVC-Anwendung, benötigt er Dienste, um Geschäftsvorgänge aufzurufen. In solchen Szenarien kann der Abhängigkeitsinjektionscontainer zum Initialisieren der Dienste verwendet werden, um die NullReferenceException zu vermeiden . Das bedeutet, dass Sie sich keine Gedanken über die Überprüfung auf Null machen müssen und die Dienste einfach vom Controller aus aufrufen müssen, als ob sie immer als Singleton oder Prototyp verfügbar (und initialisiert) wären.
quelle
In Bezug auf "Was soll ich dagegen tun?" Kann es viele Antworten geben.
Eine "formellere" Möglichkeit, solche Fehlerbedingungen während der Entwicklung zu verhindern, besteht darin, das Design in Ihrem Code vertraglich anzuwenden . Diese Mittel müssen Sie Setklasse Invarianten und / oder auch Funktion / Methode Vorbedingungen und Nachbedingungen auf Ihrem System, während der Entwicklung.
Kurz gesagt, Klasseninvarianten stellen sicher, dass es in Ihrer Klasse einige Einschränkungen gibt, die bei normaler Verwendung nicht verletzt werden (und daher wird die Klasse nicht in einen inkonsistenten Zustand versetzt). Voraussetzungen bedeuten, dass Daten, die als Eingabe für eine Funktion / Methode angegeben werden, bestimmten festgelegten Einschränkungen folgen und diese niemals verletzen müssen. Nachbedingungen bedeuten, dass eine Ausgabe von Funktionen / Methoden den festgelegten Einschränkungen erneut folgen muss, ohne sie jemals zu verletzen. Vertragsbedingungen sollten während der Ausführung eines fehlerfreien Programms niemals verletzt werden. Daher wird das vertragliche Design in der Praxis im Debug-Modus überprüft und in Releases deaktiviert , um die Leistung des entwickelten Systems zu maximieren.
Auf diese Weise können Sie
NullReferenceException
Fälle vermeiden , die auf eine Verletzung der festgelegten Einschränkungen zurückzuführen sind. Wenn Sie beispielsweise eine ObjekteigenschaftX
in einer Klasse verwenden und später versuchen, eine ihrer Methoden aufzurufen,X
die einen Nullwert hat, führt dies zuNullReferenceException
:Wenn Sie jedoch als Methodenvoraussetzung "Eigenschaft X darf niemals einen Nullwert haben" festlegen, können Sie das zuvor beschriebene Szenario verhindern:
Aus diesem Grund ist das Code Contracts- Projekt für .NET-Anwendungen vorhanden.
Alternativ kann das vertragliche Design unter Verwendung von Behauptungen angewendet werden .
UPDATE: Erwähnenswert ist, dass der Begriff von Bertrand Meyer im Zusammenhang mit seinem Entwurf der Programmiersprache Eiffel geprägt wurde .
quelle
A
NullReferenceException
wird ausgelöst, wenn wir versuchen, auf Eigenschaften eines Nullobjekts zuzugreifen, oder wenn ein Zeichenfolgenwert leer wird und wir versuchen, auf Zeichenfolgenmethoden zuzugreifen.Zum Beispiel:
Wenn auf eine Zeichenfolgenmethode einer leeren Zeichenfolge zugegriffen wird:
Wenn auf eine Eigenschaft eines Nullobjekts zugegriffen wird:
quelle
String.Empty.ToLower()
löst keine Nullreferenzausnahme aus. Es stellt eine tatsächliche Zeichenfolge dar, wenn auch eine leere (dh""
). Da dies ein Objekt zum Aufrufen hatToLower()
, wäre es nicht sinnvoll, dort eine Nullreferenzausnahme auszulösen.TL; DR: Versuchen Sie es mit
Html.Partial
anstelle vonRenderpage
Ich habe
Object reference not set to an instance of an object
festgestellt , dass ich versucht habe, eine Ansicht in einer Ansicht zu rendern , indem ich ihr ein Modell wie folgt gesendet habe:Das Debuggen zeigte, dass das Modell in MyOtherView Null war. Bis ich es geändert habe zu:
Und es hat funktioniert.
Außerdem musste ich nicht damit
Html.Partial
beginnen, dass Visual Studio manchmal fehlerhaft aussehende, schnörkellose Linien darunter wirft,Html.Partial
wenn es sich in einer anders konstruiertenforeach
Schleife befindet, obwohl es nicht wirklich ein Fehler ist:Aber ich konnte die Anwendung ohne Probleme mit diesem "Fehler" ausführen. Ich konnte den Fehler beseitigen, indem ich die Struktur der
foreach
Schleife so änderte :Obwohl ich das Gefühl habe, dass Visual Studio das kaufmännische Und und die Klammern falsch gelesen hat.
quelle
Html.Partial
nicht@Html.Partial
Null
), sodass ich wusste, dass der Fehler darin bestand, wie ich das Modell gesendet habe .Was können Sie dagegen tun?
Hier gibt es viele gute Antworten, die erklären, was eine Nullreferenz ist und wie man sie debuggt. Es gibt jedoch nur sehr wenige Möglichkeiten, um das Problem zu verhindern oder zumindest das Auffinden zu erleichtern.
Überprüfen Sie die Argumente
Beispielsweise können Methoden die verschiedenen Argumente überprüfen, um festzustellen, ob sie null sind, und eine auslösen
ArgumentNullException
, eine Ausnahme, die offensichtlich genau für diesen Zweck erstellt wurde.Der Konstruktor für das
ArgumentNullException
Even verwendet den Namen des Parameters und eine Nachricht als Argumente, damit Sie dem Entwickler genau mitteilen können, wo das Problem liegt.Verwenden Sie Tools
Es gibt auch mehrere Bibliotheken, die helfen können. "Resharper" kann Sie beispielsweise beim Schreiben von Code warnen , insbesondere wenn Sie das folgende Attribut verwenden: NotNullAttribute
Es gibt "Microsoft Code Contracts", in denen Sie Syntax wie verwenden
Contract.Requires(obj != null)
der Sie Laufzeit- und Kompilierungsprüfungen durchführen können: Einführung in Code Contracts .Es gibt auch "PostSharp", mit dem Sie einfach folgende Attribute verwenden können:
Auf diese Weise wird PostSharp zur
obj
Laufzeit auf Null gesetzt , wenn es Teil Ihres Erstellungsprozesses ist . Sehen: PostSharp-NullprüfungPlain Code-Lösung
Oder Sie können Ihren eigenen Ansatz jederzeit mit einfachem altem Code codieren. Zum Beispiel ist hier eine Struktur, mit der Sie Nullreferenzen abfangen können. Es ist nach dem gleichen Konzept modelliert wie
Nullable<T>
:Sie würden sehr ähnlich wie Sie verwenden
Nullable<T>
, außer mit dem Ziel, genau das Gegenteil zu erreichen - nicht zuzulassennull
. Hier sind einige Beispiele:NotNull<T>
wird implizit von und nach gegossen,T
sodass Sie es fast überall dort verwenden können, wo Sie es benötigen. Sie können beispielsweise einPerson
Objekt an eine Methode übergeben, die Folgendes verwendetNotNull<Person>
:Wie Sie oben wie bei nullable sehen können, würden Sie über die
Value
Eigenschaft auf den zugrunde liegenden Wert zugreifen . Alternativ können Sie eine explizite oder implizite Umwandlung verwenden. Sie können ein Beispiel mit dem folgenden Rückgabewert sehen:Oder Sie können es sogar verwenden, wenn die Methode
T
(in diesem FallPerson
) nur durch eine Umwandlung zurückgegeben wird. Der folgende Code möchte beispielsweise nur den obigen Code:Mit Erweiterung kombinieren
Kombinieren Sie
NotNull<T>
mit einer Erweiterungsmethode und Sie können noch mehr Situationen abdecken. Hier ist ein Beispiel, wie die Erweiterungsmethode aussehen kann:Und hier ist ein Beispiel, wie es verwendet werden könnte:
GitHub
Als Referenz habe ich den obigen Code auf GitHub verfügbar gemacht. Sie finden ihn unter:
https://github.com/luisperezphd/NotNull
Verwandte Sprachfunktion
In C # 6.0 wurde der "nullbedingte Operator" eingeführt, der dabei ein wenig hilft. Mit dieser Funktion können Sie auf verschachtelte Objekte verweisen. Wenn eines davon einer ist, wird
null
der gesamte Ausdruck zurückgegebennull
.Dies reduziert die Anzahl der Nullprüfungen, die Sie in einigen Fällen durchführen müssen. Die Syntax besteht darin, vor jedem Punkt ein Fragezeichen zu setzen. Nehmen Sie zum Beispiel den folgenden Code:
Stellen Sie sich vor, es
country
handelt sich um ein Objekt vom TypCountry
mit einer Eigenschaft namensState
usw. Wenncountry
,State
,County
oderCity
istnull
dannaddress will be
null. Therefore you only have to check whether
Adresseis
null`.Es ist eine großartige Funktion, aber es gibt Ihnen weniger Informationen. Es macht nicht klar, welche der 4 null ist.
Eingebaut wie Nullable?
C # hat eine nette Abkürzung für
Nullable<T>
, Sie können etwas auf Null setzen, indem Sie ein Fragezeichen nach dem Typ wie folgt setzenint?
.Es wäre schön, wenn C # so etwas wie die
NotNull<T>
obige Struktur und eine ähnliche Abkürzung hätte, vielleicht das Ausrufezeichen (!), Damit Sie etwas schreiben könnten wie :public void WriteName(Person! person)
.quelle
Interessanterweise erwähnt keine der Antworten auf dieser Seite die beiden Randfälle. Ich hoffe, es macht niemandem etwas aus, wenn ich sie hinzufüge:
Randfall Nr. 1: gleichzeitiger Zugriff auf ein Wörterbuch
Generische Wörterbücher in .NET sind nicht threadsicher und werfen manchmal ein
NullReference
oder sogar (häufiger) einKeyNotFoundException
auslösen, wenn Sie versuchen, über zwei gleichzeitige Threads auf einen Schlüssel zuzugreifen. Die Ausnahme ist in diesem Fall ziemlich irreführend.Randfall Nr. 2: unsicherer Code
Wenn a
NullReferenceException
vomunsafe
Code ausgelöst wird , können Sie sich Ihre Zeigervariablen ansehen und sie überprüfenIntPtr.Zero
oder etwas . Das ist dasselbe ("Nullzeiger-Ausnahme"), aber in unsicherem Code werden Variablen häufig in Werttypen / Arrays usw. umgewandelt, und Sie schlagen Ihren Kopf gegen die Wand und fragen sich, wie ein Werttyp dies auslösen kann Ausnahme.(Ein weiterer Grund für die Nichtverwendung von unsicherem Code, es sei denn, Sie benötigen ihn übrigens)
quelle
null
welcher?Sie können NullReferenceException auf saubere Weise mithilfe von Null-bedingten Operatoren in c # 6 beheben und weniger Code schreiben, um Nullprüfungen durchzuführen.
Es wird verwendet, um auf Null zu testen, bevor eine Mitgliedszugriffs- (?.) Oder Indexoperation (? [) Ausgeführt wird.
Beispiel
ist äquivalent zu:
Das Ergebnis ist, dass der Name null ist, wenn p null ist oder wenn p.Spouse null ist.
Andernfalls wird dem Variablennamen der Wert von p.Spouse.FirstName zugewiesen.
Weitere Informationen: Nullbedingte Operatoren
quelle
Die Fehlerzeile "Objektreferenz nicht auf eine Instanz eines Objekts festgelegt" gibt an, dass Sie einer Objektreferenz kein Instanzobjekt zugewiesen haben und dennoch auf Eigenschaften / Methoden dieses Objekts zugreifen.
Beispiel: Angenommen, Sie haben eine Klasse namens myClass, die eine Eigenschaft prop1 enthält.
Jetzt greifen Sie in einer anderen Klasse wie unten auf diese Requisite zu:
Die obige Zeile löst einen Fehler aus, weil die Referenz der Klasse myClass deklariert, aber nicht instanziiert ist oder eine Instanz des Objekts nicht der Referenz dieser Klasse zugewiesen ist.
Um dies zu beheben, müssen Sie instanziieren (Objekt der Referenz dieser Klasse zuweisen).
quelle
NullReferenceException oder Objektreferenz, die nicht auf eine Instanz eines Objekts festgelegt ist, tritt auf, wenn ein Objekt der Klasse, die Sie verwenden möchten, nicht instanziiert wird. Zum Beispiel:
Angenommen, Sie haben eine Klasse namens Student.
Stellen Sie sich nun eine andere Klasse vor, in der Sie versuchen, den vollständigen Namen des Schülers abzurufen.
Wie im obigen Code zu sehen ist, deklariert die Anweisung Student s - nur die Variable vom Typ Student. Beachten Sie, dass die Student-Klasse zu diesem Zeitpunkt nicht instanziiert wird. Wenn die Anweisung s.GetFullName () ausgeführt wird, wird daher die NullReferenceException ausgelöst.
quelle
Nun, in einfachen Worten:
Sie versuchen, auf ein Objekt zuzugreifen, das nicht erstellt wurde oder sich derzeit nicht im Speicher befindet.
Wie kann man das angehen?
Debuggen und den Debugger brechen lassen ... Sie gelangen direkt zu der defekten Variablen ... Jetzt müssen Sie dies einfach beheben. Verwenden Sie das neue Schlüsselwort an der entsprechenden Stelle.
Wenn dies bei einigen Datenbankbefehlen verursacht wird , weil das Objekt nicht vorhanden ist, müssen Sie lediglich eine Nullprüfung durchführen und damit umgehen:
Am schwierigsten ist es, wenn der GC das Objekt bereits erfasst hat. Dies tritt im Allgemeinen auf, wenn Sie versuchen, ein Objekt mithilfe von Zeichenfolgen zu finden. Wenn Sie es also anhand des Objektnamens suchen, kann es vorkommen, dass der GC dies bereits tut bereinigt ... Dies ist schwer zu finden und wird zu einem ziemlichen Problem ... Eine bessere Möglichkeit, dies zu beheben, besteht darin, während des Entwicklungsprozesses erforderlichenfalls Nullprüfungen durchzuführen. So sparen Sie viel Zeit.
Mit Suchen nach Namen meine ich, dass einige Frameworks es Ihnen ermöglichen, FIndObjects mithilfe von Zeichenfolgen zu finden, und der Code könnte folgendermaßen aussehen: FindObject ("ObjectName");
quelle
Der einfachste Weg, eine NullReferenceExeption zu reparieren, hat buchstäblich zwei Möglichkeiten. Wenn Sie beispielsweise ein GameObject mit einem angehängten Skript und einer Variablen namens rb (Rigidbody) haben, wird diese Variable beim Starten Ihres Spiels mit null gestartet.
Aus diesem Grund erhalten Sie eine NullReferenceExeption, da auf dem Computer keine Daten in dieser Variablen gespeichert sind.
Ich werde eine RigidBody-Variable als Beispiel verwenden.
Wir können Daten wirklich einfach auf verschiedene Arten hinzufügen:
dann in Ihr Skript und geben Sie Folgendes ein.
rb = GetComponent<Rigidbody>();
Diese Codezeile funktioniert am besten unter Ihren
Start()
oderAwake()
Funktionen.rb = AddComponent<RigidBody>();
Weitere Hinweise: Wenn Sie möchten, dass Unity Ihrem Objekt eine Komponente hinzufügt, und Sie möglicherweise vergessen haben, eine Komponente hinzuzufügen, können Sie
[RequireComponent(typeof(RigidBody))]
über Ihrer Klassendeklaration (dem Leerzeichen unter all Ihren Verwendungen) etwas eingeben.Viel Spaß beim Spielen!
quelle
Wenn wir häufige Szenarien betrachten, in denen diese Ausnahme ausgelöst werden kann, greifen Sie auf Eigenschaften mit dem Objekt oben zu.
Ex:
Wenn hier die Adresse null ist, erhalten Sie die NullReferenceException.
In der Praxis sollten wir daher immer die Nullprüfung verwenden, bevor wir auf Eigenschaften in solchen Objekten zugreifen (insbesondere bei generischen Objekten).
quelle
Dies ist im Grunde eine Nullreferenzausnahme . Wie Microsoft feststellt-
Was bedeutet das?
Das heißt, wenn ein Mitglied, das keinen Wert hat und wir dieses Mitglied dazu bringen, eine bestimmte Aufgabe auszuführen, wird das System zweifellos eine Nachricht werfen und sagen:
"Hey, warte, dieses Mitglied hat keine Werte, also kann es die Aufgabe, die du ihm übergibst, nicht ausführen."
Die Ausnahme selbst besagt, dass etwas verwiesen wird, dessen Wert jedoch nicht festgelegt wird. Dies bedeutet also, dass es nur bei Verwendung von Referenztypen auftritt, da Werttypen nicht nullwertfähig sind.
NullReferenceException tritt nicht auf, wenn Mitglieder vom Typ Wert verwendet werden.
Der obige Code zeigt eine einfache Zeichenfolge, die mit einem Nullwert belegt ist.
Wenn ich jetzt versuche, die Länge der Zeichenfolge str zu drucken , wird eine nicht behandelte Ausnahme vom Typ 'System.NullReferenceException' angezeigt, da Mitglied str auf null zeigt und es keine Länge von null geben kann.
' NullReferenceException ' tritt auch auf, wenn wir vergessen, einen Referenztyp zu instanziieren.
Angenommen, ich habe eine Klassen- und Mitgliedsmethode. Ich habe meine Klasse nicht instanziiert, sondern nur meine Klasse benannt. Wenn ich nun versuche, die Methode zu verwenden, gibt der Compiler einen Fehler aus oder gibt eine Warnung aus (abhängig vom Compiler).
Der Compiler für den obigen Code löst einen Fehler aus, dass die Variable obj nicht zugewiesen ist, was bedeutet, dass unsere Variable Nullwerte oder nichts hat. Der Compiler für den obigen Code löst einen Fehler aus, dass die Variable obj nicht zugewiesen ist, was bedeutet, dass unsere Variable Nullwerte oder nichts hat.
Warum tritt es auf?
NullReferenceException entsteht aufgrund unseres Fehlers, den Wert des Objekts nicht zu überprüfen. Wir lassen die Objektwerte in der Codeentwicklung oft unkontrolliert.
Es entsteht auch, wenn wir vergessen, unsere Objekte zu instanziieren. Die Verwendung dieser Methode kann auch die Verwendung von Methoden, Eigenschaften, Sammlungen usw. sein, die Nullwerte zurückgeben oder festlegen können.
Wie kann es vermieden werden?
Es gibt verschiedene Möglichkeiten und Methoden, um diese bekannte Ausnahme zu vermeiden:
Explizite Überprüfung: Wir sollten uns an die Tradition halten, Objekte, Eigenschaften, Methoden, Arrays und Sammlungen zu überprüfen, ob sie null sind. Dies kann einfach mithilfe von bedingten Anweisungen wie if-else if-else usw. implementiert werden.
Ausnahmebehandlung: Eine der wichtigsten Möglichkeiten zur Verwaltung dieser Ausnahme. Mit einfachen Try-Catch-finally-Blöcken können wir diese Ausnahme steuern und auch ein Protokoll darüber führen. Dies kann sehr nützlich sein, wenn sich Ihre Anwendung in der Produktionsphase befindet.
Null-Operatoren: Null-Coalescing-Operatoren und Null-Bedingungsoperatoren können auch nützlich sein, wenn Werte für Objekte, Variablen, Eigenschaften und Felder festgelegt werden.
Debugger: Für Entwickler haben wir die große Waffe des Debuggens dabei. Wenn wir während der Entwicklung mit NullReferenceException konfrontiert sind, können wir den Debugger verwenden, um zur Quelle der Ausnahme zu gelangen.
Eingebaute Methode: Systemmethoden wie GetValueOrDefault (), IsNullOrWhiteSpace () und IsNullorEmpty () suchen nach Nullen und weisen den Standardwert zu, wenn ein Nullwert vorhanden ist.
Hier gibt es bereits viele gute Antworten. Sie können auch eine detailliertere Beschreibung mit Beispielen in meinem Blog überprüfen .
Hoffe das hilft auch!
quelle
Wenn diese Meldung beim Speichern oder Kompilieren des Builds angezeigt wird, schließen Sie einfach alle Dateien und öffnen Sie eine beliebige Datei zum Kompilieren und Speichern.
Für mich war der Grund, dass ich die Datei umbenannt hatte und die alte Datei noch offen war.
quelle