Frage Was ist eine NullReferenceException und wie behebe ich sie?


Ich habe etwas Code und wenn es ausgeführt wird, wirft es ein NullReferenceException, Sprichwort:

Der Objektverweis wurde nicht auf eine Instanz eines Objekts festgelegt.

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


1878


Ursprung


Antworten:


Was ist die Ursache?

Endeffekt

Du versuchst etwas zu benutzen, das ist null (oder Nothing in VB.NET). Dies bedeutet, dass Sie es entweder festlegen nulloder du setzt es nie auf irgendwas.

Wie alles andere, null wird herumgereicht. Wenn es ist null  im Methode "A", könnte es sein, dass Methode "B" eine bestanden hat null  zu Methode "A".

null kann verschiedene Bedeutungen haben:

  1. Objektvariablen, die sind nicht initialisiert und daher zeigen auf nichts. Wenn Sie in diesem Fall auf Eigenschaften oder Methoden solcher Objekte zugreifen, verursacht dies a NullReferenceException.
  2. Der Entwickler ist verwenden null absichtlich darauf hinweisen, dass kein sinnvoller Wert verfügbar ist. Beachten Sie, dass C # das Konzept der Nullable-Datentypen für Variablen hat (wie Datenbanktabellen können NULL-Felder haben) - Sie können zuweisen null um ihnen anzuzeigen, dass zum Beispiel kein Wert darin gespeichert ist int? a = null; wobei das Fragezeichen angibt, dass es zulässig ist, null in der Variablen zu speichern a. Sie können das entweder mit überprüfen if (a.HasValue) {...} oder mit if (a==null) {...}. Nullable-Variablen, wie a In diesem Beispiel können Sie auf den Wert über zugreifen a.Value explizit oder einfach so normal über a.
    Hinweis dass der Zugriff über a.Value wirft ein InvalidOperationException anstelle einer NullReferenceException ob a ist null - Sie sollten die Überprüfung vorher durchführen, d. h. wenn Sie eine andere Nullwert-Variable haben int b; Dann sollten Sie Aufgaben wie if (a.HasValue) { b = a.Value; } oder kürzer if (a != null) { b = a; }.

Der Rest dieses Artikels geht ausführlicher und zeigt Fehler auf, die viele Programmierer oft machen, die zu einem führen können NullReferenceException.

Genauer

Die Laufzeit wirft einen NullReferenceException  immer bedeutet das Gleiche: Sie versuchen, eine Referenz zu verwenden, und die Referenz ist nicht initialisiert (oder war es Einmal initialisiert, aber ist nicht mehr, nicht länger initialisiert).

Dies bedeutet, dass die Referenz ist nullund Sie können nicht auf Mitglieder (wie z. B. Methoden) über a zugreifen null Referenz. Der einfachste Fall:

string foo = null;
foo.ToUpper();

Dies wird einen werfen NullReferenceException in der zweiten Zeile, weil Sie die Instanzmethode nicht aufrufen können ToUpper() auf einen string Referenz zeigt auf null.

Debuggen

Wie findest du die Quelle eines NullReferenceException? Abgesehen von der Betrachtung der Ausnahme selbst, die genau an der Stelle ausgelöst wird, an der sie auftritt, gelten die allgemeinen Regeln des Debuggens in Visual Studio: Platzieren Sie strategische Haltepunkte und Inspiziere deine VariablenEntweder indem Sie die Maus über ihre Namen bewegen, ein (Schnell-) Überwachungsfenster öffnen oder die verschiedenen Debug-Panels wie Locals und Autos verwenden.

Wenn Sie herausfinden möchten, wo der Verweis liegt oder nicht, klicken Sie mit der rechten Maustaste auf seinen Namen und wählen Sie "Alle Referenzen suchen". Sie können dann einen Haltepunkt an jeder gefundenen Stelle platzieren und Ihr Programm mit dem angehängten Debugger ausführen. Jedes Mal, wenn der Debugger einen solchen Haltepunkt unterbricht, müssen Sie ermitteln, ob Sie erwarten, dass die Referenz nicht null ist, die Variable überprüfen und überprüfen, ob sie auf eine Instanz verweist, wenn Sie dies erwarten.

Indem Sie den Programmablauf auf diese Weise verfolgen, können Sie den Ort finden, an dem die Instanz nicht null sein sollte, und warum sie nicht richtig eingestellt 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 wollen, dann 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

Speziell, in HttpContext.Current.User.Identity.Name, das HttpContext.Current könnte null sein, oder die User Eigenschaft könnte null sein, oder die Identity Eigenschaft könnte null sein.

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 den untergeordneten (Person) NULL-Verweis vermeiden möchten, könnten Sie ihn im Konstruktor des übergeordneten Objekts (Book) initialisieren.

Geschachtelte Objektinitialisierer

Dasselbe gilt für verschachtelte Objektinitialisierer:

Book b1 = new Book { Author = { Age = 45 } };

Das bedeutet in

Book b1 = new Book();
b1.Author.Age = 45;

Während new Schlüsselwort wird verwendet, es erstellt nur eine neue Instanz von Book, aber keine neue Instanz von Personso Author Das Anwesen ist ruhig null.

Nested Collection Initialisierer

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

Die Initialisierungen der verschachtelten Sammlung verhalten sich gleich:

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

Das bedeutet in

Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });

Das new Person erstellt nur eine Instanz von Person, aber die Books Sammlung ist immer noch null. Die Auflistungsinitialisierungssyntax erstellt keine Sammlung zum p1.Books, es übersetzt nur zu den p1.Books.Add(...) Aussagen.

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 / aufgeschoben)

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

Schlechte Namenskonventionen:

Wenn Sie Felder anders als lokale Namen benannt haben, haben Sie möglicherweise festgestellt, dass Sie das Feld nie initialisiert haben.

public class Form1 {
    private Customer customer;

    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 Felder mit einem Unterstrich zu versehen:

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

ASP.NET MVC leere Ansichtsmodelle

Wenn die Ausnahme auftritt, wenn auf eine Eigenschaft von verwiesen wird @Model In einer ASP.NET MVC-Ansicht müssen Sie verstehen, dass Model wird in Ihrer Aktionsmethode festgelegt, wenn Sie return eine Sicht. 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 -->

WPF Control Creation Bestellung und Ereignisse

WPF-Steuerelemente werden während des Aufrufs von erstellt InitializeComponent in der Reihenfolge, in der sie im visuellen Baum erscheinen. EIN NullReferenceException Wird im Falle von früher erstellten Steuerelementen mit Event-Handlern usw. ausgelöst, die während dieser Zeit ausgelöst werden InitializeComponent welche spät erstellten Steuerelemente referenzieren.

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 comboBox1 wird vorher erstellt label1. Ob comboBox1_SelectionChanged Wenn versucht 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!!
}

Ändern der Reihenfolge der Deklarationen im XAML (d. H. Auflistung label1 Vor comboBox1Ignorieren Probleme der Designphilosophie, würde zumindest die Lösung NullReferenceException Hier.

Darsteller mit as

var myThing = someObject as Thing;

Dies wirft keine InvalidCastException, sondern gibt ein null wenn der Cast fehlschlägt (und wenn someObject selbst null ist). Also sei dir dessen bewusst.

LINQ FirstOrDefault () und SingleOrDefault ()

Die einfachen Versionen First() und Single() Ausnahmen auslösen, wenn es nichts gibt. Die "OrDefault" -Versionen geben in diesem Fall null zurück. Also sei dir dessen bewusst.

für jede

foreach löst aus, wenn Sie versuchen, die Nullsammlung zu iterieren. Normalerweise verursacht durch unerwartete null Ergebnis von Methoden, die Sammlungen zurückgeben.

 List<int> list = null;    
 foreach(var v in list) { } // exception

Realistischere Beispiel - Wählen Sie Knoten aus XML-Dokument. Wird ausgelöst, wenn Knoten nicht gefunden werden, aber das anfängliche Debugging zeigt, dass alle Eigenschaften gültig sind:

 foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))

Wege zu vermeiden

Explizit nachsehen null und ignoriere Nullwerte.

Wenn Sie erwarten, dass die Referenz manchmal null ist, können Sie nachsehen, ob es sich um eine Referenz handelt null vor dem Zugriff auf Instanzmitglieder:

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

Explizit nachsehen null und geben Sie einen Standardwert an.

Methoden, die Sie erwarten, dass eine Instanz zurückgegeben werden kann nullzum Beispiel, wenn das gesuchte Objekt nicht gefunden werden kann. In diesem Fall können Sie einen Standardwert auswählen:

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

Explizit nachsehen null aus Methodenaufrufen und eine benutzerdefinierte Ausnahme auslösen.

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

Benutzen Debug.Assert wenn ein Wert nie sein sollte null, um das Problem früher als die Ausnahme auftritt.

Wenn Sie während der Entwicklung wissen, dass eine Methode vielleicht kann, aber nie zurückkehren sollte nullkannst du benutzen Debug.Assert() so schnell wie möglich zu brechen, wenn es 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.
}

Obwohl diese Überprüfung endet nicht in deinem Release-Build, verursacht, dass es das wirft NullReferenceException wieder wann book == null zur Laufzeit im Freigabemodus.

Benutzen GetValueOrDefault() für Nullable-Werttypen, 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 Koaleszenzoperator null: ?? [C #] oder If() [VB].

Die Abkürzung für einen Standardwert, wenn a null ist aufgetreten:

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 sichere Navigation oder Elvis (nach seiner Form) bezeichnet. Wenn der Ausdruck auf der linken Seite des Operators null ist, wird die rechte Seite nicht ausgewertet und stattdessen wird null zurückgegeben. Das bedeutet Fälle wie folgt:

var title = person.Title.ToUpper();

Wenn die Person keinen Titel hat, wird eine Ausnahme ausgelöst, weil sie versucht anzurufen ToUpper auf eine Eigenschaft mit einem Nullwert.

In C # 5 und darunter kann dies geschützt 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 eine kürzere Syntax dafür ein:

var title = person.Title?.ToUpper();

Dies wird dazu führen, dass die Titelvariable ist nullund der Anruf zu ToUpper wird nicht gemacht, wenn person.Title ist null.

Natürlich Du immer noch muss überprüfen title für null oder verwenden Sie den Null-Bedingung-Operator zusammen mit dem Null-Koaleszenz-Operator (??) um einen Standardwert zu liefern:

// 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 für Arrays, die Sie verwenden können ?[i] wie folgt:

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

Dies wird Folgendes tun: Wenn myIntArray NULL ist, gibt der Ausdruck null zurück und Sie können es sicher überprüfen. Wenn es ein Array enthält, wird dasselbe wie folgt ausgeführt: elem = myIntArray[i]; und gibt das i zurückth Element.

Spezielle Techniken zum Debuggen und Beheben von Null-Derefs in Iteratoren

C # unterstützt "Iteratorblöcke" (in anderen populären Sprachen "Generatoren" genannt). Null-Dereferenzierungs-Ausnahmen können in Iterator-Blöcken aufgrund verzögerter Ausführung 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) { ... }

Ob whatever Ergebnisse in null dann MakeFrob wird werfen. Nun, Sie könnten denken, dass das Richtige zu tun 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? Weil der Iterator-Block nicht wirklich Lauf bis zum foreach! Der Anruf zu GetFrobs gibt einfach ein Objekt zurück, das wenn es iteriert wird wird den Iterator-Block ausführen.

Durch das Schreiben eines Null-Tests wie diesem verhindern Sie die Null-Dereferenzierung, aber Sie verschieben die Null-Argument-Ausnahme auf den Punkt des Iteration, nicht auf den Punkt der Anruf, und das ist sehr verwirrend zu debuggen.

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 eine private Hilfsmethode mit der Iteratorblocklogik und eine öffentliche Oberflächenmethode, die die Nullprüfung durchführt und den Iterator zurückgibt. Jetzt, wenn GetFrobs wird aufgerufen, der Null-Check passiert sofort und dann GetFrobsForReal Wird ausgeführt, wenn die Sequenz iteriert wird.

Wenn Sie die Referenzquelle für LINQ to Objects untersuchen, werden Sie sehen, dass diese Technik durchgängig verwendet wird. Es ist etwas klobiger zu schreiben, aber es macht Debugging Nichtigkeit Fehler viel einfacher. Optimieren Sie Ihren Code für die Bequemlichkeit des Anrufers, nicht die Bequemlichkeit des Autors.

Eine Anmerkung zu Null-Dereferenzierungen in unsicheren Code

C # hat einen "unsicheren" Modus, der, wie der Name andeutet, extrem gefährlich ist, da die normalen Sicherheitsmechanismen, die Speichersicherheit und Typsicherheit bieten, nicht erzwungen werden. Sie sollten keinen unsicheren Code schreiben, es sei denn, Sie haben ein gründliches und tiefes Verständnis davon, wie Speicher funktioniert.

Im unsicheren Modus sollten Sie zwei wichtige Fakten beachten:

  • Dereferenzierung einer Null Zeiger erzeugt die gleiche Ausnahme wie Dereferenzierung einer Null Referenz
  • Dereferenzierung eines ungültigen Nicht-Null-Zeigers kann erzeuge diese Ausnahme unter bestimmten Umständen

Um zu verstehen, warum das so ist, hilft es zu verstehen, wie .NET überhaupt Null-Dereferenzierungs-Ausnahmen erzeugt. (Diese Details gelten für .NET unter Windows, andere Betriebssysteme verwenden ähnliche Mechanismen.)

Speicher wird in Windows virtualisiert; Jeder Prozess erhält einen virtuellen Speicherplatz von vielen "Seiten" des Arbeitsspeichers, die vom Betriebssystem verfolgt werden. Auf jeder Seite des Speichers sind Flags gesetzt, die bestimmen, wie es verwendet werden kann: Lesen von, Schreiben in, Ausführen usw. Das niedrigste Seite wird als "einen Fehler erzeugen, wenn jemals in irgendeiner Weise verwendet" markiert.

Sowohl ein Nullzeiger als auch eine Nullreferenz in C # werden intern als die Zahl Null dargestellt, und jeder Versuch, ihn in seinen entsprechenden Speicher zu dereferenzieren, führt dazu, dass das Betriebssystem einen Fehler erzeugt. Die .NET-Laufzeitumgebung erkennt diesen Fehler und wandelt ihn in die Null-Dereferenzierungsausnahme um.

Aus diesem Grund erzeugt die Dereferenzierung eines Null- und eines Null-Verweises die gleiche Ausnahme.

Was ist mit dem zweiten Punkt? Dereferenzierung irgendein Ungültiger Zeiger, der auf die unterste Seite des virtuellen Speichers fällt, verursacht den gleichen Betriebssystemfehler und damit die gleiche Ausnahme.

Warum macht das Sinn? Nehmen wir an, wir haben eine Struktur mit zwei Ints und einen nicht verwalteten Zeiger mit dem Wert null. Wenn wir versuchen, das zweite int in der Struktur zu dereferenzieren, versucht die CLR nicht, auf den Speicher an der Stelle null zuzugreifen; Es wird auf den Speicher an Position vier zugreifen. Aber logisch ist das eine Null-Dereferenz, weil wir zu dieser Adresse gelangen über die Null.

Wenn Sie mit unsicheren Code arbeiten und eine Null-Dereferenzierungs-Ausnahme erhalten, beachten Sie, dass der betreffende Zeiger nicht null sein muss. Es kann ein beliebiger Ort auf der untersten Seite sein, und diese Ausnahme wird erzeugt.


2107



NullReference-Ausnahme - Visual Basic

Das NullReference Exception zum Visual Basic unterscheidet sich nicht von dem in C #. Immerhin melden beide die gleiche Ausnahme, die im .NET Framework definiert ist, das sie beide verwenden. Für Visual Basic einzigartige Ursachen sind selten (vielleicht nur eine).

Diese Antwort verwendet Visual Basic-Begriffe, -Syntax und -Kontext. Die verwendeten Beispiele stammen aus einer großen Anzahl von Stack Overflow-Fragen. Dies dient der Maximierung der Relevanz durch Verwendung der Arten von Situationen, die oft in Posts gesehen werden. Ein bisschen mehr Erklärung ist auch für diejenigen, die es brauchen könnten. Ein Beispiel, das deinem ähnlich ist sehr wahrscheinlich hier aufgelistet.

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 a verursacht NullReferenceException (NRE), wie man es findet, wie man es repariert und wie man es vermeidet. Ein NRE kann viele Ursachen haben, daher ist es unwahrscheinlich, dass dies deine einzige Begegnung ist.
  2. Die Beispiele (von Stack Overflow-Posts) zeigen nicht immer den besten Weg, etwas zu tun.
  3. In der Regel wird das einfachste Mittel verwendet.

Grundlegende Bedeutung

Die Nachricht "Objekt nicht auf eine Objektinstanz festgelegt" bedeutet, dass Sie versuchen, ein Objekt zu verwenden, das nicht initialisiert wurde. Dies läuft auf eines von ihnen hinaus:

  • Dein Code erklärt eine Objektvariable, aber nicht initialisieren es (eine Instanz erstellen oder 'instanziieren'es)
  • Etwas, von dem Ihr Code annahm, würde ein Objekt initialisieren, tat es nicht
  • Möglicherweise hat ein anderer Code ein noch verwendetes Objekt vorzeitig ungültig gemacht

Die Ursache finden

Da das Problem eine Objektreferenz ist, ist das NothingDie Antwort ist, sie zu untersuchen, um herauszufinden, welche. Bestimmen Sie dann, warum es nicht initialisiert ist. Halten Sie die Maus über die verschiedenen Variablen und Visual Studio (VS) zeigt ihre Werte an - der Täter wird sein Nothing.

IDE debug display

Sie sollten auch alle Try / Catch-Blöcke aus dem relevanten Code entfernen, insbesondere solche, in denen sich im Catch-Block nichts befindet. Dies führt dazu, dass Ihr Code abstürzt, wenn er versucht, ein Objekt zu verwenden, das Nothing. Das ist, was du willst weil es das genaue identifizieren wird Lage des Problems und ermöglichen es Ihnen, das verursachende Objekt zu identifizieren.

EIN MsgBox im Fang, der anzeigt Error while... wird wenig helfen. Diese Methode führt auch zu sehr schlecht Stapelüberlauffragen, da Sie die tatsächliche Ausnahme, das betroffene Objekt oder die Codezeile, in der es auftritt, nicht beschreiben können.

Sie können auch die Locals Window (Debug -> Windows -> Einheimische) um Ihre Objekte zu untersuchen.

Sobald Sie wissen, was und wo das Problem ist, ist es normalerweise relativ einfach zu beheben und schneller als eine neue Frage zu posten.

Siehe auch:

Beispiele und Rechtsmittel

Klassenobjekte / Erstellen einer Instanz

Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE

Das Problem ist, dass Dim erstellt kein CashRegister Objekt; es deklariert nur eine Variable namens reg von diesem Typ. Erklären eine Objektvariable und Erstellen eines Beispiel sind zwei verschiedene Dinge.

Abhilfe

Das New Der Operator kann oft 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: Unterlassen Sie benutzen Dim wieder in einer Prozedur, einschließlich des Konstruktors (Sub New):

Private reg As CashRegister
'...

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

Dies wird ein erstellen lokal Variable, reg, die nur in diesem Kontext (sub) existiert. Das reg variabel mit Modulebene Scope die du überall sonst verwenden wirst Nothing.

Vermisse die New Betreiber ist die Ursache Nr. 1 von NullReference Exceptions in den überprüften Stack Overflow-Fragen gesehen.

Visual Basic versucht, den Prozess mit wiederholt zu löschen New: Verwendung der New Operator erstellt ein Neu Objekt und Anrufe Sub New - der Konstruktor - wo Ihr Objekt eine andere Initialisierung durchführen kann.

Deutlich sein, Dim (oder Private) nur erklärt eine Variable und ihre Type. Das Umfang der Variable - ob sie für das gesamte Modul / Klasse existiert oder lokal zu einer Prozedur ist - wird bestimmt durch woher es ist erklärt. Private | Friend | Public definiert die Zugriffsebene nicht Umfang.

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 mehrere 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) {}

Anmerkung: Beginnend mit VS 2010, wenn ein lokales Array unter Verwendung eines Literals und Option Infer, das As <Type> und New Elemente sind optional:

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. Klassen- / Modulebene-Deklarationen erfordern immer noch 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, aber das FooObjekte darin haben nicht.

Abhilfe

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

Verwendung einer List(Of T) wird es sehr schwierig machen, 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 gibt - Listen, Wörterbuch usw.) müssen ebenfalls instanziiert oder erstellt werden.

Private myList As List(Of String)
..
myList.Add("ziggy")           ' NullReference

Sie erhalten die gleiche Ausnahme aus dem gleichen Grund - myList wurde nur deklariert, aber keine Instanz erstellt. Das Heilmittel ist das gleiche:

myList = New List(Of String)

' Or create an instance when declared:
Private myList As New List(Of String)

Eine allgemeine Aufsicht 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

Beide Verfahren führen zu einem NRE, weil barList wird nur deklariert, nicht instanziiert. Erstellen einer Instanz von Foo erstellt auch keine Instanz des internen barList. Möglicherweise war es 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

Wie zuvor ist dies nicht korrekt:

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

Das Arbeiten mit Datenbanken bietet viele Möglichkeiten für eine NullReference, da es viele Objekte geben kann (Command, Connection, Transaction, Dataset, DataTable, DataRows....) sofort benutzt. Hinweis: Es spielt keine Rolle, welchen Datenprovider Sie verwenden - MySQL, SQL Server, OleDB usw. - der Konzepte sind gleich.

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

Wie zuvor, der ds Das Dataset-Objekt wurde deklariert, eine Instanz wurde jedoch nie erstellt. Das DataAdapter wird ein existierendes füllen DataSet, nicht eins erstellen. In diesem Fall seit ds ist eine lokale Variable, Die IDE warnt Sie dass dies passieren könnte:

img

Wenn es als Variable auf Modul- / Klassenebene deklariert wird, wie es bei con, der Compiler kann nicht wissen, ob das Objekt von einer Upstream-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 ist hier ein Problem: Employees vs Employee. Es gab keine DataTable Name "Mitarbeiter" erstellt, also a NullReferenceException Ergebnisse, die versuchen, darauf zuzugreifen. Ein anderes mögliches Problem ist anzunehmen, dass es sein wird Items was nicht so sein kann, wenn das SQL eine WHERE-Klausel enthält.

Abhilfe

Da dies eine Tabelle verwendet, verwenden Tables(0) vermeidet Schreibfehler. Untersuchen Rows.Count kann 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

Fill ist eine Funktion, die die Anzahl von zurückgibt Rows betroffen, die auch getestet werden können:

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 DataAdapter wird liefern TableNames wie im vorherigen Beispiel gezeigt, aber es analysiert keine Namen aus der SQL- oder Datenbanktabelle. Als Ergebnis, ds.Tables("TICKET_RESERVATION") verweist auf eine nicht vorhandene Tabelle.

Das Abhilfe ist das gleiche, verweisen Sie die Tabelle nach Index:

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

Siehe auch DataTable-Klasse.


Objektpfade / geschachtelt

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

Der Code testet nur Items während beide myFoo und Bar kann auch nichts sein. Das Abhilfe ist es, die gesamte Kette oder den Pfad von Objekten nacheinander zu testen:

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

AndAlso ist wichtig. Nachfolgende Tests werden nicht nach dem ersten durchgeführt False Bedingung ist aufgetreten. Dies ermöglicht es dem Code, sicher in das Objekt (die Objekte) auf einer "Ebene" zu einem Zeitpunkt zu bohren und zu bewerten myFoo.Bar nur nach (und wenn) myFoo wird bestimmt, um gültig zu sein. Objektketten oder Pfade können beim Codieren komplexer Objekte relativ lang werden:

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

Es ist nicht möglich, irgendetwas "stromabwärts" von a zu referenzieren null Objekt. Dies gilt auch für Kontrollen:

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

Hier, myWebBrowser oder Document könnte nichts oder sein formfld1 Element möglicherweise nicht vorhanden.


Benutzeroberflächensteuerelemente

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 in einem oder mehreren UI-Steuerelementen etwas ausgewählt hat. ListBox1.SelectedItem kann gut sein Nothing, damit ListBox1.SelectedItem.ToString wird zu einem NRE führen.

Abhilfe

Daten validieren, bevor Sie sie verwenden (auch verwenden Option Strict und 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-Formulare

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 eine ziemlich häufige Möglichkeit, eine NRE zu erhalten. In C #, je nachdem, wie es codiert ist, meldet die IDE dies Controls existiert nicht im aktuellen Kontext oder "kann nicht auf nicht-statische Mitglieder verweisen". Bis zu einem gewissen Grad ist dies nur eine VB-Situation. Es ist auch komplex, weil es zu einer Fehlerkaskade kommen kann.

Die Arrays und Sammlungen können auf diese Weise nicht initialisiert werden. Dieser Initialisierungscode wird ausgeführt Vor Der Konstruktor erstellt das Form oder der Controls. Als Ergebnis:

  • Listen und Sammlungen sind einfach leer
  • Das Array enthält fünf Elemente von Nichts
  • Das somevar Die Zuweisung führt zu einer sofortigen NRE, da Nothing keine a .Text Eigentum

Ein späteres Verweisen auf Array-Elemente führt zu einem NRE. Wenn Sie dies tun in Form_Load, aufgrund eines seltsamen Fehlers, die IDE nicht dürfen Melden Sie die Ausnahme, wenn es passiert. Die Ausnahme wird angezeigt später wenn Ihr Code versucht, das Array zu verwenden. Diese "stille Ausnahme" ist detailliert in diesem Post. Für unsere Zwecke ist der Schlüssel, dass wenn etwas katastrophales beim Erstellen eines Formulars passiert (Sub New oder Form Load Ereignis), Ausnahmen können nicht gemeldet werden, der Code beendet die Prozedur und zeigt nur das Formular an.

Da kein anderer Code in deinem Sub New oder Form Load Ereignis wird nach dem NRE laufen, sehr viele andere Dinge kann nicht initialisiert werden.

Sub Form_Load(..._
   '...
   Dim name As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

Hinweis Dies gilt für alle Kontroll- und Komponentenreferenzen, 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 seltsam, dass VB keine Warnung gibt, aber die Abhilfe ist erklären die Container auf der Formularebene, aber initialisieren sie in Formular laden Ereignishandler, wenn die Steuerelemente machen existieren. Dies kann in. Getan werden Sub New Solange der Code nach dem InitializeComponent Anruf:

' 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 Holz. Alle Steuerelemente, die sich in einem Containersteuerelement (wie einem GroupBox oder Panel) wird nicht gefunden in Me.Controls; Sie befinden sich in der Controls-Auflistung dieses Panels oder dieser GroupBox. Es wird auch kein Steuerelement zurückgegeben, wenn der Name des Steuerelements falsch geschrieben ist ("TeStBox2"). In solchen Fällen, Nothing wird wieder in diesen Array-Elementen gespeichert, und es wird eine NRE angezeigt, wenn Sie versuchen, darauf zu verweisen.

Diese sollten jetzt leicht zu finden sein, da Sie wissen, wonach Sie suchen: VS shows you the error of your ways

"Button2" befindet sich auf a Panel

Abhilfe

Anstelle von indirekten Verweisen auf den Namen mit den Formularen ControlsSammlung, verwenden Sie die Kontrollreferenz:

' 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, dassNicht alle Pfade geben einen Wert zurück und a NullReferenceException kann dazu führen". Sie können die Warnung unterdrücken, indem Sie ersetzen Exit Function mit Return Nothing, aber das löst das Problem nicht. Alles, was versucht, die Rückkehr wann zu verwenden someCondition = False wird zu einem NRE führen:

bList = myFoo.BarList()
For Each b As Bar in bList      ' EXCEPTION
      ...

Abhilfe

Ersetzen Exit Function in der Funktion mit Return bList. Rückkehr eines leer  List ist nicht das Gleiche wie die Rückkehr Nothing. Wenn es eine Chance gibt, dass ein zurückgegebenes Objekt sein kann Nothing, testen Sie bevor Sie es benutzen:

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

Schlecht implementiert Try / Catch

Ein schlecht implementierter Try / Catch kann verbergen, wo das Problem liegt und neue ergeben:

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, aber es zeigt auch, dass ein leeres Objekt nicht sinnvoll ist Catch.

Es gibt ein zusätzliches Komma in der SQL (nach 'Mailadresse'), was zu einer Ausnahme bei .ExecuteReader. Nach dem Catch tut nichts, Finally versucht aufzuräumen, aber da kannst du nicht Close eine Null DataReader Objekt, ein brandneues NullReferenceException Ergebnisse.

Ein leeres Catch Block ist der Spielplatz des Teufels. Dieser OP war verblüfft, warum er eine NRE in der Finally Block. In anderen Situationen eine leere Catch kann dazu führen, dass etwas anderes weiter stromabwärts drunter und drüber geht und Sie Zeit damit verbringen, die falschen Dinge an der falschen Stelle für das Problem zu betrachten. (Die oben beschriebene "stille Ausnahme" bietet denselben Unterhaltungswert.)

Abhilfe

Verwenden Sie keine leeren Try / Catch-Blöcke - lassen Sie den Code abstürzen, so dass Sie a) die Ursache identifizieren können, b) den Standort identifizieren und c) ein geeignetes Mittel anwenden können. Try / Catch-Blöcke sind nicht dazu gedacht, Ausnahmen von der Person zu verstecken, die dazu berechtigt ist, sie zu reparieren - der Entwickler.


DBNull ist nicht dasselbe wie Nothing

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...

Das IsDBNull Funktion wird verwendet, um zu testen, ob a Wert ist gleich System.DBNull: Von MSDN:

Der System.DBNull-Wert gibt an, dass das Objekt fehlende oder nicht vorhandene Daten darstellt. DBNull ist nicht identisch mit Nothing, was darauf hinweist, dass eine Variable noch nicht initialisiert wurde.

Abhilfe

If row.Cells(0) IsNot Nothing Then ...

Wie zuvor können Sie auf nichts 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
       ...

FirstOrDefault Gibt das erste Element oder den Standardwert zurück Nothing für Referenztypen und nie 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 CheckBox mit chkName kann nicht gefunden werden (oder existiert in a GroupBox), dann chk wird Nothing sein 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 ein paar Macken in regelmäßigen Abständen gesehen:

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"

Ob dgvBooks hat AutoGenerateColumns = TrueEs werden die Spalten erstellt, aber sie werden nicht benannt. Daher schlägt der obige Code fehl, wenn er auf die Namen verweist.

Abhilfe

Benennen Sie die Spalten manuell oder verweisen Sie auf den 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 dein DataGridView hat AllowUserToAddRows wie True (der Standard), der Cells in der leeren / neuen Reihe am Ende wird alles enthalten Nothing. Die meisten Versuche, die Inhalte zu verwenden (z. B. ToString) wird zu einem NRE führen.

Abhilfe

Benutze einen For/Each Schleife und teste die IsNewRow Eigenschaft, um zu bestimmen, ob es diese letzte Zeile ist. Das funktioniert ob AllowUserToAddRows ist wahr oder nicht:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

Wenn du a verwendest For n Schleife, ändern Sie die Anzahl der Zeilen oder verwenden Sie sie Exit For wann IsNewRow ist wahr.


Meine Einstellungen (StringCollection)

Unter bestimmten Umständen versuchen Sie, einen Artikel aus zu verwenden My.Settings die ein StringCollection kann bei der ersten Verwendung zu einer NullReference führen. Die Lösung ist die gleiche, aber nicht so offensichtlich. Erwägen:

My.Settings.FooBars.Add("ziggy")         ' foobars is a string collection

Da VB Einstellungen für Sie verwaltet, ist es sinnvoll zu erwarten, dass die Sammlung initialisiert wird. Dies wird jedoch nur dann möglich sein, wenn Sie zuvor der Sammlung einen Anfangseintrag hinzugefügt haben (im Einstellungen-Editor). Da die Sammlung (scheinbar) initialisiert wird, wenn ein Element hinzugefügt wird, bleibt es bestehen Nothing Wenn im Einstellungs-Editor keine Elemente zum Hinzufügen vorhanden sind.

Abhilfe

Initialisieren Sie die Settings-Auflistung in den Formularen Load Event-Handler, falls / wann benötigt:

If My.Settings.FooBars Is Nothing Then
    My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If

Normalerweise Settings Die Sammlung muss nur beim ersten Ausführen der Anwendung initialisiert werden. Eine alternative Abhilfe besteht darin, Ihrer Sammlung einen Anfangswert hinzuzufügen Projekt -> Einstellungen | FooBars, speichern Sie das Projekt und entfernen Sie den falschen Wert.


Schlüsselpunkte

Du hast wahrscheinlich das vergessen New Operator.

oder

Etwas, von dem Sie annahmen, dass es einwandfrei funktioniert, um ein initialisiertes Objekt an Ihren Code zurückzugeben, tat es nicht.

Ignoriere Compilerwarnungen (niemals) und verwende sie Option Strict On (immer).


MSDN-Nullreferenz-Ausnahme


273



Ein anderes Szenario ist, wenn Sie ein Null-Objekt in ein Werttyp. Zum Beispiel der folgende Code:

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

Es wird ein werfen NullReferenceException auf der Besetzung. Es scheint ziemlich offensichtlich in dem obigen Beispiel, aber das kann in mehr "spät-verbindlich" komplizierte Szenarien passieren, wo das Null-Objekt von Code zurückgegeben wurde, den Sie nicht besitzen, und die Besetzung wird zum Beispiel von einem automatischen System generiert.

Ein Beispiel dafür ist dieses einfache ASP.NET-Bindungsfragment mit dem Calendar-Steuerelement:

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

Hier, SelectedDate ist in der Tat eine Eigenschaft von DateTime Typ - von der Calendar Web Control-Typ, und die Bindung könnte perfekt Null zurückgeben. Der implizite ASP.NET-Generator erstellt ein Codeelement, das dem oben angegebenen Zeichencode entspricht. Und das wird eine erhöhen NullReferenceException das ist ziemlich schwer zu erkennen, weil es in ASP.NET generiertem Code liegt, der gut kompiliert ...


217



Es bedeutet, dass die betreffende Variable auf nichts ausgerichtet ist. Ich könnte das so erzeugen:

SqlConnection connection = null;
connection.Open();

Das wird den Fehler verursachen, weil ich die Variable deklariert habe "connection"Es wird nicht auf etwas hingewiesen. Wenn ich versuche, das Mitglied anzurufen"Open"Es gibt keinen Hinweis darauf, es zu lösen, und es wird den Fehler werfen.

Um diesen Fehler zu vermeiden:

  1. Initialisieren Sie Ihre Objekte immer, bevor Sie versuchen, etwas mit ihnen zu tun.
  2. Wenn Sie nicht sicher sind, ob das Objekt null ist, überprüfen Sie es mit object == null.

JetBrains 'Resharper-Tool wird jede Stelle in Ihrem Code identifizieren, die die Möglichkeit eines Null-Referenzfehlers bietet, so dass Sie einen Null-Check durchführen können. Dieser Fehler ist die größte Fehlerquelle, IMHO.


146



Das bedeutet, dass Ihr Code eine Objektreferenzvariable verwendet hat, die auf null gesetzt wurde (d. H., Sie referenzierte keine tatsächliche Objektinstanz).

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
}

135



Beachten Sie, dass die Ursache in .NET unabhängig vom Szenario immer dieselbe ist:

Sie versuchen, eine Referenzvariable zu verwenden, deren Wert ist Nothing/null. Wenn der Wert ist Nothing/null Für die Referenzvariable bedeutet dies, dass sie keinen Verweis auf eine Instanz eines Objekts enthält, das auf dem Heap existiert.

Sie haben der Variablen nie etwas zugewiesen, nie eine Instanz des der Variablen zugewiesenen Wertes erstellt oder die Variable gleich gesetzt Nothing/null manuell, oder Sie haben eine Funktion aufgerufen, mit der die Variable festgelegt wird Nothing/null für dich.


90



Ein Beispiel für diese ausgelöste Ausnahme ist: Wenn Sie versuchen, etwas zu überprüfen, ist das null.

Beispielsweise:

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-Laufzeitumgebung wird eine NullReferenceException auslösen, wenn Sie versuchen, eine Aktion für etwas auszuführen, das nicht instanziiert wurde, d. H. Den obigen Code.

Im Vergleich zu einer ArgumentNullException, die normalerweise als Verteidigungsmaßnahme ausgelöst wird, wenn eine Methode erwartet, dass das, was an sie übergeben wird, nicht null ist.

Weitere Informationen sind in C # NullReferenceException und Null-Parameter.


76



Wenn Sie einen Referenztyp nicht initialisiert haben und eine seiner Eigenschaften festlegen oder lesen möchten, wird ein NullReferenceException.

Beispiel:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Sie können dies einfach vermeiden, indem Sie prüfen, ob die Variable nicht null ist:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Um zu verstehen, warum eine NullReferenceException ausgelöst wird, ist es wichtig, den Unterschied zu kennen Werttypen und Referenztypen.

Also, wenn du damit zu tun hast Werttypen, NullReferenceExceptions kann nicht auftreten. Obwohl Sie im Umgang mit wachsam sein müssen Referenztypen!

Nur Referenztypen können, wie der Name andeutet, Referenzen enthalten oder buchstäblich auf nichts (oder "null") zeigen. 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
  • Integrierte Typen
  • Gleitkommatypen
  • Dezimal
  • Bool
  • Benutzerdefinierte Strukturen

72