Was ist eine NullReferenceException und wie behebe ich sie?


1875

Ich habe einen Code und wenn er ausgeführt wird, wirft er ein NullReferenceExceptionund sagt:

Der Objektverweis wurde nicht auf eine Instanz eines Objekts festgelegt.

Was bedeutet das und was kann ich tun, um diesen Fehler zu beheben?


Der Ausnahmehelfer in VS 2017 ist hilfreicher bei der Diagnose der Ursache dieser Ausnahme - blogs.msdn.microsoft.com/visualstudio/2016/11/28/… unter Neuer Ausnahmehelfer .
Zev Spitz

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 null in Verfahren „A“, könnte es diese Methode „B“ sein , eine übergeben null zu Verfahren „A“.

null kann verschiedene Bedeutungen haben:

    1. 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.
    1. 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 NullReferenceException 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 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:

var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member

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

public class Person 
{
    public int Age { get; set; }
}
public class Book 
{
    public Person Author { get; set; }
}
public class Example 
{
    public void Foo() 
    {
        Book b1 = new Book();
        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 = new Book 
{ 
   Author = { Age = 45 } 
};

Dies bedeutet

Book b1 = new Book();
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.

Initialisierer für verschachtelte Sammlungen

public class Person 
{
    public ICollection<Book> Books { get; set; }
}
public class Book 
{
    public string Title { get; set; }
}

Die verschachtelte Auflistung Initializersverhält sich wie folgt:

Person p1 = new Person 
{
    Books = {
         new Book { Title = "Title1" },
         new Book { Title = "Title2" },
    }
};

Dies bedeutet

Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { 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 = new Person[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 = new long[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)

public class Person 
{
    public string Name { get; set; }
}
var people = new List<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

public class Demo
{
    public event EventHandler StateChanged;

    protected virtual void OnStateChanged(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. 

öffentliche Klasse Form1 {Privatkunde Kunde;

private void Form1_Load(object sender, EventArgs e) 
{
    Customer customer = new Customer();
    customer.Name = "John";
}

private void Button_Click(object sender, EventArgs e)
{
    MessageBox.Show(customer.Name);
}

}}

Dies kann gelöst werden, indem Sie der Konvention folgen, um Feldern einen Unterstrich voranzustellen:

    private Customer _customer;

ASP.NET-Seitenlebenszyklus:

public partial class Issues_Edit : System.Web.UI.Page
{
    protected TestIssue myIssue;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
             // Only called on first load, not when button clicked
             myIssue = new TestIssue(); 
        }
    }

    protected void SaveButton_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 NullReferenceException
string 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:

// Controller
public class Restaurant:Controller
{
    public ActionResult Search()
    {
        return View();  // Forgot the provide a Model here.
    }
}

// Razor view 
@foreach (var restaurantSearch in Model.RestaurantSearch)  // Throws.
{
}

<p>@Model.somePropertyName</p> <!-- Also throws -->

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 -->
    <ComboBox Name="comboBox1" 
              Margin="10"
              SelectedIndex="0" 
              SelectionChanged="comboBox1_SelectionChanged">
       <ComboBoxItem Content="Item 1" />
       <ComboBoxItem Content="Item 2" />
       <ComboBoxItem Content="Item 3" />
    </ComboBox>

    <!-- Label declared later -->
    <Label Name="label1" 
           Content="Label"
           Margin="10" />
</Grid>

Hier comboBox1wird vorher erstellt label1. Wenn comboBox1_SelectionChangedversucht wird, auf `label1 zu verweisen, wurde es noch nicht erstellt.

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}

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 as Thing;

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:

void PrintName(Person p)
{
    if (p != null) 
    {
        Console.WriteLine(p.Name);
    }
}

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:

string GetCategory(Book b) 
{
    if (b == null)
        return "Unknown";
    return b.Category;
}

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:

string GetCategory(string bookTitle) 
{
    var book = library.FindBook(bookTitle);  // This may return null
    if (book == null)
        throw new BookNotFoundException(bookTitle);  // Your custom exception
    return 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:

string GetTitle(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 code

    return book.Title; // Will never throw NullReferenceException in Debug mode.
}

Diese Prüfung endet jedoch nicht in Ihrem Release-Build , sodass sie zur Laufzeit im Release-Modus NullReferenceExceptionerneut book == nullausgelöst wird.

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 = new DateTime(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:

IService CreateService(ILogger log, Int32? frobPowerLevel)
{
   var serviceImpl = new MyService(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 check
int titleLength = 0;
if (title != null)
    titleLength = title.Length; // If title is null, this would throw NullReferenceException

// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;

Ebenso können Sie für Arrays ?[i]Folgendes verwenden:

int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");

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:

public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
    for (int i = 0; i < count; ++i)
    yield return 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 THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
   if (f == null) 
      throw new ArgumentNullException("f", "factory must not be null");
   for (int i = 0; i < count; ++i)
      yield return 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 THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
   // No yields in a public method that throws!
   if (f == null) 
       throw new ArgumentNullException("f", "factory must not be null");
   return GetFrobsForReal(f, count);
}
private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count)
{
   // Yields in a private method
   Debug.Assert(f != null);
   for (int i = 0; i < count; ++i)
        yield return 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.


55
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:

  1. 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.
  2. Die Beispiele (aus Stack Overflow-Posts) zeigen nicht immer, wie man überhaupt etwas am besten macht.
  3. 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.

IDE-Debug-Anzeige

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.

Siehe auch:

Beispiele und Abhilfemaßnahmen

Klassenobjekte / Erstellen einer Instanz

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 As New 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:

Private reg As CashRegister         ' Declare
  ...
reg = New CashRegister()            ' Create instance

Hinweis: Sie nicht verwenden , Dimwieder in einem Verfahren, einschließlich dem Konstruktor ( Sub New):

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

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

Weitere Informationen finden Sie unter:


Arrays

Arrays müssen auch instanziiert werden:

Private arr as String()

Dieses Array wurde nur deklariert, nicht erstellt. Es gibt verschiedene Möglichkeiten, ein Array zu initialisieren:

Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}

' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}

Hinweis: Ab VS 2010 sind beim Initialisieren eines lokalen Arrays mit einem Literal und Option Inferdie Elemente As <Type>und Newoptional:

Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {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 As Double() = {1.5, 2, 9.9, 18, 3.14}

Beispiel: Array von Klassenobjekten

Dim arrFoo(5) As Foo

For i As Integer = 0 To arrFoo.Count - 1
   arrFoo(i).Bar = i * 10       ' Exception
Next

Das Array wurde erstellt, die darin enthaltenen FooObjekte jedoch nicht.

Abhilfe

For i As Integer = 0 To arrFoo.Count - 1
    arrFoo(i) = New Foo()         ' Create Foo instance
    arrFoo(i).Bar = i * 10
Next

Die Verwendung eines List(Of T)Testaments macht es ziemlich schwierig, ein Element ohne ein gültiges Objekt zu haben:

Dim FooList As New List(Of Foo)     ' List created, but it is empty
Dim f As Foo                        ' Temporary variable for the loop

For i As Integer = 0 To 5
    f = New Foo()                    ' Foo instance created
    f.Bar =  i * 10
    FooList.Add(f)                   ' Foo object added to list
Next

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.

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 As New List(Of String)

Ein häufiges Versehen ist eine Klasse, die eine Sammlung verwendet Type:

Public Class Foo
    Private barList As List(Of Bar)

    Friend Function BarCount As Integer
        Return barList.Count
    End Function

    Friend Sub AddItem(newBar As Bar)
        If barList.Contains(newBar) = False Then
            barList.Add(newBar)
        End If
    End Function

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:

Public Sub New         ' Constructor
    ' Stuff to do when a new Foo is created...
    barList = New List(Of Bar)
End Sub

Dies ist nach wie vor falsch:

Public Sub New()
    ' Creates another barList local to this procedure
     Dim barList As New List(Of Bar)
End Sub

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, 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 As Integer

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:

img

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.

Abhilfe

Dim ds As New DataSet

Beispiel 2

ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")

txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)

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 > 0 Then
    txtID.Text = ds.Tables(0).Rows(0).Item(1)
    txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If

Fillist eine Funktion, die die Anzahl der RowsBetroffenen zurückgibt, die auch getestet werden kann:

If da.Fill(ds, "Employees") > 0 Then...

Beispiel 3

Dim da As New 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 As New DataSet
da.Fill(ds)

If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then

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:

If ds.Tables(0).Rows.Count > 0 Then

Siehe auch DataTable-Klasse .


Objektpfade / Verschachtelt

If myFoo.Bar.Items IsNot Nothing Then
   ...

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:

If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....

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:

myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")

Es ist nicht möglich, irgendetwas 'stromabwärts' eines nullObjekts zu referenzieren . Dies gilt auch für Kontrollen:

myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"

Hier myWebBrowseroder Documentkönnte nichts sein oder das formfld1Element kann nicht existieren.


UI-Steuerelemente

Dim cmd5 As New 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 validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
    (ListBox1.SelectedItems.Count > 0) AndAlso
    (ComboBox2.SelectedItems.Count > 0) AndAlso
    (DateTime.TryParse(expiry.Text, expiry) Then

    '... do stuff
Else
    MessageBox.Show(...error message...)
End If

Alternativ können Sie verwenden (ComboBox5.SelectedItem IsNot Nothing) AndAlso...


Visual Basic Forms

Public Class 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 As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}

    ' Immediate NRE:
    Private somevar As String = 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 As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

Beachten Sie, dass dies für alle Steuerungs- und Komponentenreferenzen gilt, die diese illegal machen, wo sie sind:

Public Class Form1

    Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
    Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
    Private studentName As String = TextBox13.Text

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 Newsolange sich Ihr Code nach dem InitializeComponentAufruf befindet:

' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String

' 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: VS zeigt Ihnen den Fehler Ihrer Wege

"Button2" befindet sich auf a Panel

Abhilfe

Verwenden Sie anstelle indirekter namentlicher Verweise in der Formularsammlung Controlsdie Steuerelementreferenz:

' Declaration
Private 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 As New List(Of Bars)        ' Declared and created

Public Function BarList() As List(Of Bars)
    bars.Clear
    If someCondition Then
        For n As Integer = 0 to someValue
            bars.Add(GetBar(n))
        Next n
    Else
        Exit Function
    End If

    Return bars
End Function

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()
For Each b As Bar in bList      ' EXCEPTION
      ...

Abhilfe

Ersetzen Sie Exit Functionin der Funktion durch Return bList. Das Zurückgeben eines Leerzeichens List 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:

 bList = myFoo.BarList()
 If bList IsNot Nothing Then...

Try / Catch schlecht implementiert

Ein schlecht implementierter Try / Catch kann verbergen, wo das Problem liegt, und zu neuen führen:

Dim dr As SqlDataReader
Try
    Dim lnk As LinkButton = TryCast(sender, LinkButton)
    Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
    Dim eid As String = 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()
    End If
    command = New SqlCommand(sqlQry, connection)

    'More code fooing and barring

    dr = command.ExecuteReader()
    If dr.Read() Then
        lblFirstName.Text = Convert.ToString(dr("FirstName"))
        ...
    End If
    mpe.Show()
Catch

Finally
    command.Dispose()
    dr.Close()             ' <-- NRE
    connection.Close()
End Try

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

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not 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 Nothing Then ...

Nach wie vor können Sie auf Nothing und dann auf einen bestimmten Wert testen:

If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then

Beispiel 2

Dim getFoo = (From f In dbContext.FooBars
               Where f.something = something
               Select f).FirstOrDefault

If Not IsDBNull(getFoo) Then
    If 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 Nothing Then...

Kontrollen

Dim chk As CheckBox

chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
    Return chk
End If

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:

dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True       ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"

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:

dgvBooks.Columns(0).Visible = True

Beispiel 2 - Vorsicht vor der NewRow

xlWorkSheet = xlWorkBook.Sheets("sheet1")

For i = 0 To myDGV.RowCount - 1
    For j = 0 To myDGV.ColumnCount - 1
        For k As Integer = 1 To myDGV.Columns.Count
            xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
            xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
        Next
    Next
Next

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:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' 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 Is Nothing Then
    My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If

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).


MSDN NullReference-Ausnahme


226

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:

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

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 ...


7
Großer Fang. Einzeiler Weg zu vermeiden:DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Serge Shultz

160

Dies bedeutet, dass die betreffende Variable auf nichts zeigt. Ich könnte das so erzeugen:

SqlConnection connection = null;
connection.Open();

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:

  1. Initialisieren Sie Ihre Objekte immer, bevor Sie versuchen, etwas damit zu tun.
  2. 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.


3
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
}

96

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.


87

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.

Weitere Informationen finden Sie in C # NullReferenceException und Null Parameter .


87

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:

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.

Referenztypen (diese müssen überprüft werden):

  • dynamisch
  • Objekt
  • Zeichenfolge

Werttypen (Sie können diese einfach ignorieren):

  • Numerische Typen
  • Integrale Typen
  • Gleitkommatypen
  • Dezimal
  • Bool
  • Benutzerdefinierte Strukturen

6
-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 :

class Book {
    public string Name { get; set; }
}
class Car { }

Car mycar = new Car();
Book mybook = mycar as Book;   // Incompatible conversion --> mybook = null

Console.WriteLine(mybook.Name);   // NullReferenceException

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:

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}

2
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:

string value = 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 ()


1
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.

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 myStringWert null. Dies kann überprüft werden, indem Sie das Überwachungsfenster betrachten oder Ausdrücke im Direktfenster ausführen .

var x = myString.Trim();

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


59

Simon Mourier gab dieses Beispiel :

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

wobei eine Unboxing- Konvertierung (Umwandlung) von object (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 false zu 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:

public static void MyExtension(this object x)
{
  x.ToString();
}

Der folgende Code ist problematisch:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

Diese Fälle entstehen aufgrund der speziellen Regeln, die die Laufzeit beim Boxen von Nullable<>Instanzen verwendet.


42

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 = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

Der Vollständigkeit halber DataContext-Klasse

public class DataContext : DbContext 
{
    public DbSet<Contact> Contacts {get; set;}
}

und Kontaktentitätsklasse. Manchmal sind Entitätsklassen Teilklassen, sodass Sie sie auch in anderen Dateien erweitern können.

public partial class Contact 
{
    public string Name {get; set;}
}

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 ()


41

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.

Ein etwas ausführliches Beispiel finden Sie unter " NullReferenceException beim Testen eines benutzerdefinierten AuthorizationAttribute ".


40

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.

public class MyController
{
    private ServiceA serviceA;
    private ServiceB serviceB;

    public MyController(ServiceA serviceA, ServiceB serviceB)
    {
        this.serviceA = serviceA;
        this.serviceB = serviceB;
    }

    public void MyMethod()
    {
        // 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();
    }
}

6
-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; }

public void InvokeX()
{
    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]
protected void ObjectInvariant () 
{
    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 .

UPDATE: Erwähnenswert ist, dass der Begriff von Bertrand Meyer im Zusammenhang mit seinem Entwurf der Programmiersprache Eiffel geprägt wurde .


2
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:

  1. Wenn auf eine Zeichenfolgenmethode einer leeren Zeichenfolge zugegriffen wird:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
  2. Wenn auf eine Eigenschaft eines Nullobjekts zugegriffen wird:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 

2
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 = new MyEntity();
}
@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 = new MyEntity();
}
@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:

@inherits System.Web.Mvc.WebViewPage
@{
    ViewBag.Title = "Entity Index";
    List<MyEntity> MyEntities = new List<MyEntity>();
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
}
<div>
    @{
        foreach(var M in MyEntities)
        {
            // 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 in MyEntities){
    ...
}

Obwohl ich das Gefühl habe, dass Visual Studio das kaufmännische Und und die Klammern falsch gelesen hat.


Sie wollten Html.Partialnicht@Html.Partial
John Saunders

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.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("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:

public void DoSometing([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]
public struct NotNull<T> where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull<T> notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull<T>(T value)
    {
        return new NotNull<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 exception
NotNull<Person> person = new Person(); // OK
NotNull<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 = new Person { Name = "John" };
WriteName(person);

public static void WriteName(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();

public static NotNull<Person> GetPerson()
{
    return new Person { 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();

public static Person GetPerson()
{
    return new Person { 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]
public static class NotNullExtension
{
    public static T NotNull<T>(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("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:

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 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).


2
Wirf niemals NullReferenceException
John Saunders

@ 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)


5
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.

Weitere Informationen: Nullbedingte Operatoren


9

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.

public Class myClass
{
   public int prop1 {get;set;}
}

Jetzt greifen Sie in einer anderen Klasse wie unten auf diese Requisite zu:

public class Demo
{
     public void 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).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}

4

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.

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

Stellen Sie sich nun eine andere Klasse vor, in der Sie versuchen, den vollständigen Namen des Schülers abzurufen.

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

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.


3

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?

  1. 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.

  2. 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
    }
  3. 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");


3
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.
Akash Gutha

2
docs.unity3d.com/ScriptReference/… überprüfen Sie den Link und korrigieren Sie sich selbst mr.expert: p
Akash Gutha

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:

  1. 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.
  2. 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!


-1

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

-3

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.

class Program
{
    static void Main(string[] args)
    {
        string str = null;
        Console.WriteLine(str.Length);
        Console.ReadLine();
    }
}

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).

class Program
{
    static void Main(string[] args)
    {
        MyClass1 obj;
        obj.foo();  //Use of unassigned local variable 'obj'
    }
}

public class MyClass1
{
    internal void 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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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!


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.