Ich habe Code und wenn er ausgeführt wird, wirft er ein NullReferenceException
mit den Worten:
Der Objektverweis wurde nicht auf eine Instanz eines Objekts festgelegt.
Was bedeutet das und was kann ich tun, um diesen Fehler zu beheben?
Sie versuchen, etwas zu verwenden, das null
(oder Nothing
in VB.NET) ist. Dies bedeutet, dass Sie entweder null
festgelegt haben oder dass Sie überhaupt nichts festgelegt haben.
Wie alles andere wird auch null
herumgereicht. Wenn es null
inMethode "A" ist, könnte es sein, dass Methode "B" ein null
anübergeben hat. Methode "A".
null
kann verschiedene Bedeutungen haben:
NullReferenceException
.null
absichtlich angeben, dass kein sinnvoller Wert verfügbar ist. Beachten Sie, dass C # das Konzept nullfähiger Datentypen für Variablen hat (Datenbanktabellen können nullfähige Felder haben) - Sie können ihnen null
zuweisen Gibt an, dass kein Wert gespeichert ist, z. B. int? a = null;
, wobei das Fragezeichen angibt, dass in der Variablen a
der Wert null gespeichert werden darf. Sie können dies entweder mit if (a.HasValue) {...}
oder mit if (a==null) {...}
überprüfen. Nullfähige Variablen, wie in diesem Beispiel a
, ermöglichen den expliziten Zugriff auf den Wert über a.Value
oder ganz normal über a
.a.Value
darauf zugreifen, wird anstelle von InvalidOperationException
ein NullReferenceException
ausgegeben, wenn a
null
ist int b;
dann sollten Sie Aufgaben wie if (a.HasValue) { b = a.Value; }
oder kürzere if (a != null) { b = a; }
ausführen.Der Rest dieses Artikels geht ausführlicher auf Fehler ein, die viele Programmierer häufig machen und die zu einem NullReferenceException
führen können.
Die Laufzeit, die ein NullReferenceException
auslöst immer bedeutet dasselbe: Sie versuchen, eine Referenz zu verwenden, und die Referenz ist nicht initialisiert (oder es wareinmalinitialisiert, ist abernicht mehrinitialisiert).
Dies bedeutet, dass die Referenz null
lautet und Sie nicht über eine null
-Referenz auf Mitglieder (z. B. Methoden) zugreifen können. Der einfachste Fall:
string foo = null;
foo.ToUpper();
Dadurch wird in der zweiten Zeile ein NullReferenceException
ausgegeben, da Sie die Instanzmethode ToUpper()
nicht für einen string
-Verweis aufrufen können, der auf null
verweist.
Wie finden Sie die Quelle eines NullReferenceException
? Abgesehen von 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 den Mauszeiger darüber halten Öffnen Sie ein (Quick) Watch-Fenster oder verwenden Sie die verschiedenen Debug-Fenster wie Locals und Autos.
Wenn Sie herausfinden möchten, wo sich die Referenz befindet 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 Ort einen Haltepunkt setzen und Ihr Programm mit dem angehängten Debugger ausführen. Bei jeder Unterbrechung des Debuggers an einem solchen Haltepunkt 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 wurde.
Einige häufige Szenarien, in denen die Ausnahme ausgelöst werden kann:
ref1.ref2.ref3.member
Wenn ref1 oder ref2 oder ref3 null ist, erhalten Sie ein NullReferenceException
. Wenn Sie das Problem lösen möchten, ermitteln Sie, 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.Name
kann HttpContext.Current
null sein, oder die Eigenschaft User
kann null sein, oder die Eigenschaft Identity
kann null sein.
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 Nullreferenz child (Person) vermeiden möchten, können Sie sie im Konstruktor des übergeordneten Objekts (Book) initialisieren.
Gleiches gilt für verschachtelte Objektinitialisierer:
Book b1 = new Book { Author = { Age = 45 } };
Dies übersetzt zu
Book b1 = new Book();
b1.Author.Age = 45;
Während das Schlüsselwort new
verwendet wird, wird nur eine neue Instanz von Book
erstellt, jedoch keine neue Instanz von Person
. Daher ist die Eigenschaft Author
immer noch null
.
public class Person {
public ICollection<Book> Books { get; set; }
}
public class Book {
public string Title { get; set; }
}
Die verschachtelten Auflistungsinitialisierer verhalten sich wie folgt:
Person p1 = new Person {
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Dies übersetzt zu
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
Der new Person
erstellt nur eine Instanz von Person
, die Books
-Auflistung ist jedoch immer noch null
. Die Syntax des Auflistungsinitialisierers erstellt keine Auflistung für p1.Books
, sondern übersetzt nur die Anweisungen p1.Books.Add(...)
.
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
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.
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.
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
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.
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
}
}
Wenn Sie Felder anders benannt haben als Einheimische, 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 durch Befolgen der Konvention zum Präfixieren von Feldern mit einem Unterstrich gelöst werden:
private Customer _customer;
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!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
Wenn die Ausnahme beim Verweisen auf eine Eigenschaft von @Model
in einer ASP.NET MVC-Ansicht auftritt, müssen Sie verstehen, dass Model
in Ihrer Aktionsmethode festgelegt wird, wenn Sie return
eine Ansicht aufrufen. 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-Steuerelemente werden beim Aufruf von InitializeComponent
in der Reihenfolge erstellt, in der sie in der visuellen Struktur angezeigt werden. Bei früh erstellten Steuerelementen mit Ereignishandlern usw., die während von NullReferenceException
ausgelöst werden und auf neu erstellte Steuerelemente verweisen, wird ein InitializeComponent
ausgelöst.
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 wird comboBox1
vor label1
erstellt. Wenn comboBox1_SelectionChanged
versucht, auf `label1 zu verweisen, wurde es noch nicht erstellt.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Das Ändern der Reihenfolge der Deklarationen in der XAML (d. H. Auflisten von label1
vor comboBox1
, Ignorieren von Problemen der Entwurfsphilosophie, würde zumindest die NullReferenceException
hier beheben.
as
var myThing = someObject as Thing;
Dies löst keine InvalidCastException aus, sondern gibt null
zurück, wenn die Umwandlung fehlschlägt (und someObject selbst null ist). Also sei dir dessen bewusst.
Die einfachen Versionen First()
und Single()
lösen Ausnahmen aus, wenn nichts vorhanden ist. Die "OrDefault" -Versionen geben in diesem Fall null zurück. Also sei dir dessen bewusst.
foreach
wird ausgelöst, wenn Sie versuchen, die Nullsammlung zu wiederholen. Normalerweise verursacht durch unerwartete null
-Ergebnisse von Methoden, die Auflistungen 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"))
null
und ignorieren Sie Nullwerte.Wenn Sie erwarten, dass die Referenz manchmal null ist, können Sie überprüfen, ob sie null
ist, bevor Sie auf Instanzmitglieder zugreifen:
void PrintName(Person p) {
if (p != null) {
Console.WriteLine(p.Name);
}
}
null
und geben Sie einen Standardwert an.Von Ihnen erwartete Methoden, die eine Instanz zurückgeben, können null
zurückgeben, z. B. wenn das gesuchte Objekt nicht gefunden werden kann. Sie können einen Standardwert zurückgeben, wenn dies der Fall ist:
string GetCategory(Book b) {
if (b == null)
return "Unknown";
return b.Category;
}
null
in Methodenaufrufen 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;
}
Debug.Assert
, wenn ein Wert niemals null
lauten soll, um das Problem früher zu beheben, als die Ausnahme auftritt.Wenn Sie während der Entwicklung wissen, dass eine Methode möglicherweise null
zurückgeben kann, aber niemals sollte, können Sie Debug.Assert()
verwenden, um den Vorgang so schnell wie möglich abzubrechen, wenn er 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 Prüfung wird nicht in Ihrem Release-Build enden bewirkt, dass NullReferenceException
erneut ausgelöst wird, wenn book == null
zur Laufzeit im Release-Modus ausgeführt wird.
GetValueOrDefault()
für nullfähige Werttypen, um einen Standardwert bereitzustellen, wenn sie null
sind.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
??
[C #] oder If()
[VB].Die Abkürzung zum Bereitstellen eines Standardwerts, wenn ein null
auftritt:
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;
}
?.
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, ToUpper
für eine Eigenschaft mit einem Nullwert aufzurufen.
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 dazu eine kürzere Syntax ein:
var title = person.Title?.ToUpper();
Dies führt dazu, dass die Titelvariable null
ist und der Aufruf von ToUpper
nicht erfolgt, wenn person.Title
null
ist.
Natürlich müssen Siestilltitle
auf null prüfen oder den Operator null zusammen mit dem Operator null coalescing (??
) 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]
wie folgt verwenden:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Dies führt Folgendes aus: Wenn myIntArray null ist, gibt der Ausdruck null zurück und Sie können ihn sicher überprüfen. Wenn es ein Array enthält, verhält es sich wie folgt: elem = myIntArray[i];
und gibt das i zurückth Element.
Eingeführt in C # 8 führen Nullkontexttypen und nullfähige Referenztypen statische Analysen für Variablen durch und geben eine Compilerwarnung aus, wenn ein Wert möglicherweise null sein kann oder auf null gesetzt wurde. Die nullfähigen Referenztypen ermöglichen es, dass Typen explizit die Erlaubnis erhalten, null zu sein.
Der nullfähige Anmerkungskontext und der nullfähige Warnkontext können für ein Projekt mithilfe des Nullable-Elements in Ihrer csproj-Datei festgelegt werden. Dieses Element konfiguriert, wie der Compiler die Nullwertfähigkeit von Typen interpretiert und welche Warnungen generiert werden. Gültige Einstellungen sind:
Ein nullwertfähiger Referenztyp wird mit der gleichen Syntax wie nullwertfähige Werttypen angegeben: Ein ?
wird an den Typ der Variablen angehängt.
C # unterstützt "Iteratorblöcke" (in einigen anderen gängigen Sprachen "Generatoren" genannt). NULL-Dereferenzierungsausnahmen können in Iteratorblöcken aufgrund der verzögerten 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) { ... }
Wenn whatever
zu null
führt, wirft MakeFrob
. 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? Denn der Iteratorblock führterst dannaus, wenn foreach
! Der Aufruf von GetFrobs
gibt einfach ein Objekt zurück, dasbei Iterationden Iteratorblock ausführt.
Indem Sie eine Nullprüfung wie diese schreiben, verhindern Sie die Null-Dereferenzierung, aber Sie verschieben die Nullargumentausnahme an den Punkt derIteration, nicht an den Punkt dercall, und das istsehr 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 also eine private Hilfsmethode mit der Iteratorblocklogik und eine öffentliche Oberflächenmethode, die die Nullprüfung durchführt und den Iterator zurückgibt. Wenn jetzt GetFrobs
aufgerufen wird, erfolgt die Nullprüfung sofort, und dann wird GetFrobsForReal
ausgeführt, wenn die Sequenz iteriert wird.
Wenn Sie die Referenzquelle für LINQ to Objects untersuchen, werden Sie feststellen, dass diese Technik durchgehend verwendet wird. Das Schreiben ist etwas umständlicher, aber das Debuggen von Nullitätsfehlern ist viel einfacher. Optimieren Sie Ihren Code zum Nutzen des Anrufers, nicht zum Nutzen des Autors.
C # hat einen "unsicheren" Modus, der, wie der Name schon sagt, extrem gefährlich ist, da die normalen Sicherheitsmechanismen, die für Speichersicherheit und Typensicherheit sorgen, nicht erzwungen werden. Sie sollten keinen unsicheren Code schreiben, es sei denn, Sie haben ein gründliches und tiefes Verständnis der Funktionsweise des Speichers..
Im unsicheren Modus sollten Sie zwei wichtige Fakten kennen:
Um zu verstehen, warum das so ist, ist es hilfreich zu verstehen, wie .NET überhaupt keine Dereferenzierungsausnahmen erzeugt. (Diese Details gelten für .NET unter Windows. Andere Betriebssysteme verwenden ähnliche Mechanismen.)
Der Speicher wird in Windows virtualisiert. Jeder Prozess erhält einen virtuellen Speicherplatz mit vielen "Seiten" Speicher, die vom Betriebssystem überwacht werden. Auf jeder Speicherseite sind Flags gesetzt, die bestimmen, wie sie verwendet werden dürfen: Auslesen, Beschreiben, Ausführen usw. DieniedrigsteSeite wird als "Erzeugt einen Fehler, wenn jemals auf irgendeine Weise verwendet" 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 dann diesen Fehler und wandelt ihn in die Null-Dereferenzierungsausnahme um.
Aus diesem Grund führt die Dereferenzierung sowohl eines Nullzeigers als auch einer Nullreferenz zu derselben Ausnahme.
Was ist mit dem zweiten Punkt? Die Dereferenzierung vonjedemungültigen Zeiger, 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 einem nicht verwalteten Zeiger gleich null. Wenn wir versuchen, das zweite int in der Struktur zu dereferenzieren, versucht die CLR nicht, auf den Speicher an Position Null zuzugreifen. Es greift auf den Speicherplatz vier zu. Aber logischerweise ist dies eine Null-Dereferenzierung, weil wir zu dieser Adresseüberdie Null gelangen.
Wenn Sie mit unsicherem Code arbeiten und eine Null-Dereferenzierungsausnahme erhalten, beachten Sie, 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.
Der _NullReference Exception
_ fürVisual Basicunterscheidet sich nicht von dem inC #. Immerhin melden beide dieselbe in .NET Framework definierte Ausnahme, die sie beide verwenden. In Visual Basic eindeutige Ursachen sind selten (möglicherweise nur eine).
Diese Antwort verwendet Visual Basic-Begriffe, -Syntax und -Kontext. Die verwendeten Beispiele stammen aus einer Vielzahl früherer Fragen zum Stapelüberlauf. Dies dient dazu, die Relevanz zu maximieren, indem die Arten von Situationen verwendet werden, die häufig in Posts auftreten. Für diejenigen, die es vielleicht brauchen, gibt es eine etwas ausführlichere Erklärung. Ein Beispiel, das Ihrem ähnlich ist, ist sehr wahrscheinlich hier aufgelistet.
Hinweis:
NullReferenceException
(NRE) hat, wie Sie es finden, wie Sie es beheben und wie Sie es vermeiden. Ein NRE kann auf viele Arten verursacht werden, sodass dies wahrscheinlich nicht Ihre einzige Begegnung ist.Die Meldung "Objekt wurde nicht auf eine Instanz von Object festgelegt" bedeutet, dass Sie versuchen, ein Objekt zu verwenden, das nicht initialisiert wurde. Daraus ergibt sich Folgendes:
Da das Problem eine Objektreferenz ist, die Nothing
ist, besteht die Antwort darin, sie zu untersuchen, um herauszufinden, welche. Bestimmen Sie dann, warum es nicht initialisiert wird. Halten Sie die Maus über die verschiedenen Variablen und Visual Studio (VS) zeigt ihre Werte an - der Schuldige ist Nothing
.
Sie sollten auch alle Try/Catch-Blöcke aus dem entsprechenden Code entfernen, insbesondere solche, in denen sich nichts im Catch-Block befindet. Dies führt zu einem Absturz des Codes, wenn versucht wird, ein Objekt zu verwenden, das Nothing
ist.Dies ist, was Sie wollenweil es das genaue Ort des Problems identifiziert und es Ihnen ermöglicht, das Objekt zu identifizieren, das es verursacht.
Ein MsgBox
im Catch, der _Error while...
_ anzeigt, wird wenig helfen. Diese Methode führt auch zu sehr schlecht Fragen zum Stapelüberlauf, da Sie die tatsächliche Ausnahme, das betreffende Objekt oder sogar die Codezeile, in der sie auftritt, nicht beschreiben können.
Sie können auch den _Locals Window
_ (Debug -> Windows -> Locals) verwenden, um Ihre Objekte zu untersuchen.
Sobald Sie wissen, wo und wo das Problem liegt, ist es in der Regel recht einfach und schneller zu beheben als das Posten einer neuen Frage.
Siehe auch:
_Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
_
Das Problem ist, dass Dim
kein CashRegister erstellt object; Es wird nur eine Variable mit dem Namen reg
dieses Typs deklariert. Deklarieren einer Objektvariablen und Erstellen einer Instanz sind zwei verschiedene Dinge.
Abhilfe
Der Operator New
kann häufig zum Erstellen der Instanz verwendet werden, 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 sinnvoll ist, die Instanz später zu erstellen:
_Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
_
Hinweis:Verwenden Sie Dim
in einer Prozedur, einschließlich des Konstruktors (_Sub New
_), nicht erneut:
_Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
_
Dadurch wird die Variable localreg
erstellt, die nur in diesem Kontext (sub) vorhanden ist. Die Variable reg
mit der Modulebene Scope
, die Sie überall sonst verwenden werden, bleibt Nothing
.
Das Fehlen des Operators
New
ist die häufigste Ursache für _NullReference Exceptions
_, die in den Stapelüberlauf-Fragen besprochen wurde.Visual Basic versucht, den Prozess wiederholt mit
New
zu verdeutlichen: Mit dem OperatorNew
wird einnewobject und ruftSub New
- den Konstruktor auf, in dem Ihr Objekt eine andere Initialisierung durchführen kann.
Um klar zu sein, nur Dim
(oder Private
) deklariert eine Variable und ihre Type
. Das Scope der Variablen - ob für das gesamte Modul/die gesamte Klasse vorhanden oder für eine Prozedur lokal - wird durch where deklariert. _Private | Friend | Public
_ definiert die Zugriffsebene, nicht Scope.
Weitere Informationen finden Sie unter:
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 Infer
_ die Elemente _As <Type>
_ und New
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. Für Deklarationen auf Klassen-/Modulebene ist weiterhin _As <Type>
_ mit _Option Strict
_ erforderlich:
_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 Foo
-Objekte 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 von List(Of T)
macht es ziemlich schwierig, ein Element ohne 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:
.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 - myList
wurde 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 Type
verwendet:
_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 Prozeduren führen zu einem NRE, da barList
nur deklariert und nicht instanziiert wird. Beim Erstellen einer Instanz von Foo
wird auch keine Instanz von barList
erstellt. 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
_
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)
Class .
Das Arbeiten mit Datenbanken bietet viele Möglichkeiten für eine NullReference, da viele Objekte (Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) gleichzeitig verwendet werden können.Hinweis:Es spielt keine Rolle, welchen Datenprovider Sie verwenden - MySQL, SQL Server, OleDB usw. - die Konzepte sind die 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 wurde das Dataset-Objekt ds
deklariert, es wurde jedoch nie eine Instanz erstellt. Der DataAdapter
füllt einen vorhandenen DataSet
und erstellt keinen. In diesem Fall, da ds
eine lokale Variable ist, warnt die IDE Sie, dass dies passieren könnte:
Wenn der Compiler als Modul-/Klassenvariable deklariert ist, wie es bei con
der Fall zu sein scheint, kann er nicht wissen, ob das Objekt durch eine vorgelagerte Prozedur erstellt wurde. Ignorieren Sie keine Warnungen.
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 wurde kein DataTable
mit dem Namen "Employee" erstellt, sodass ein NullReferenceException
-Ergebnis beim Versuch, darauf zuzugreifen, angezeigt wird. Ein weiteres mögliches Problem ist die Annahme, dass es Items
gibt, was möglicherweise nicht der Fall ist, wenn die SQL eine WHERE-Klausel enthält.
Abhilfe
Da dies eine Tabelle verwendet, werden durch die Verwendung von Tables(0)
Rechtschreibfehler vermieden. Das Untersuchen von _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 der betroffenen Rows
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
_
DataAdapter
liefert TableNames
, wie im vorherigen Beispiel gezeigt, analysiert jedoch keine Namen aus der SQL- oder Datenbanktabelle. Daher verweist ds.Tables("TICKET_RESERVATION")
auf eine nicht vorhandene Tabelle.
DasRemedyist dasselbe, referenzieren Sie die Tabelle nach Index:
_If ds.Tables(0).Rows.Count > 0 Then
_
Siehe auch DataTable-Klasse .
_If myFoo.Bar.Items IsNot Nothing Then
...
_
Der Code testet nur Items
, während sowohl myFoo
als auch Bar
auch Nothing sein können. Mitremedykönnen Sie die gesamte Kette oder den gesamten Pfad von Objekten einzeln testen:
_If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
_
AndAlso
ist wichtig. Nachfolgende Tests werden nicht ausgeführt, sobald die erste False
-Bedingung vorliegt. Auf diese Weise kann der Code sicher eine Ebene nach der anderen in die Objekte "bohren" und _myFoo.Bar
_ nur dann auswerten, wenn (und wenn) myFoo
als gültig ermittelt wurde. 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, auf ein null
-Objekt 'nachgeordnet' zu verweisen. Dies gilt auch für Kontrollen:
_myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
_
Hier könnte myWebBrowser
oder Document
Nothing sein, oder das _formfld1
_ -Element ist möglicherweise nicht vorhanden.
_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)
_
Unter anderem geht dieser Code nicht davon aus, dass der Benutzer in einem oder mehreren Steuerelementen der Benutzeroberfläche möglicherweise nichts ausgewählt hat. _ListBox1.SelectedItem
_ kann durchaus Nothing
sein, daher führt _ListBox1.SelectedItem.ToString
_ zu einem NRE.
Abhilfe
Überprüfen Sie die Daten, bevor Sie sie verwenden (verwenden Sie auch die Parameter _Option Strict
_ und SQL):
_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 _(ComboBox5.SelectedItem IsNot Nothing) AndAlso...
_ verwenden.
_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 recht gebräuchlicher Weg, um ein NRE zu erhalten. In C # meldet das IDE je nach Codierung, dass Controls
im aktuellen Kontext nicht vorhanden ist oder "nicht auf nicht statische Member verweisen kann". In gewissem Maße handelt es sich also um eine reine VB-Situation. Es ist auch komplex, da es zu einer Ausfallkaskade kommen kann.
Die Arrays und Auflistungen können nicht auf diese Weise initialisiert werden. Dieser Initialisierungscode wird ausgeführt bevor der Konstruktor das Form
oder das Controls
erstellt. Als Ergebnis:
somevar
-Zuweisung führt zu einem sofortigen NRE, da Nothing keine _.Text
_ -Eigenschaft besitztWenn Sie später auf Array-Elemente verweisen, wird ein NRE erstellt. Wenn Sie dies in _Form_Load
_ tun, meldet das IDE möglicherweise nicht die Ausnahme, wenn sie auftritt. Die Ausnahme wird später angezeigt, wenn Ihr Code versucht, das Array zu verwenden. Diese "stille Ausnahme" ist ausführlich in diesem Beitrag . Für unsere Zwecke ist der Schlüssel, dass, wenn beim Erstellen eines Formulars (_Sub New
_ oder _Form Load
_) etwas Katastrophales passiert, Ausnahmen möglicherweise nicht gemeldet werden, der Code die Prozedur verlässt und nur das Formular anzeigt.
Da kein anderer Code in Ihrem Ereignis _Sub New
_ oder _Form Load
_ nach dem NRE ausgeführt wird, kann 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
_
HinweisDies gilt für alle Verweise auf Steuerelemente und Komponenten, die diese unzulässig machen, sofern sie:
_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 ausgibt, aber das Mittel ist,die Container auf Formularebene zu deklarieren, aberinitialisierensie in der Ereignisbehandlungsroutine für das Laden von Formularen, wenn die Steuerelementedovorhanden sind. Dies kann in _Sub New
_ erfolgen, solange sich Ihr Code nach dem Aufruf von InitializeComponent
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 (z. B. GroupBox
oder Panel
), werden in _Me.Controls
_ nicht gefunden. 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 wird Nothing
erneut in diesen Array-Elementen gespeichert, und es wird eine NRE ausgegeben, wenn Sie versuchen, darauf zu verweisen.
Diese sollten jetzt, da Sie wissen, wonach Sie suchen, leicht zu finden sein:
"Button2" befindet sich auf einem Panel
Abhilfe
Verwenden Sie die Steuerelementreferenz anstelle von indirekten Verweisen nach Namen, die die Controls
-Auflistung des Formulars verwenden:
_' 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...})
_
_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 IDE Sie warnt, dass 'nicht alle Pfade einen Wert zurückgeben und ein NullReferenceException
resultieren kann'. Sie können die Warnung unterdrücken, indem Sie _Exit Function
_ durch _Return Nothing
_ ersetzen, aber das löst das Problem nicht. Alles, was versucht, die Rückgabe zu verwenden, wenn _someCondition = False
_ zu einem NRE führt:
_bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
_
Abhilfe
Ersetzen Sie _Exit Function
_ in der Funktion durch _Return bList
_. Das Zurückgeben eines leerList
ist nicht dasselbe wie das Zurückgeben von Nothing
. Wenn die Möglichkeit besteht, dass ein zurückgegebenes Objekt Nothing
sein kann, testen Sie es, bevor Sie es verwenden:
_ bList = myFoo.BarList()
If bList IsNot Nothing Then...
_
Ein schlecht implementiertes Try/Catch kann das Problem verbergen 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 der Fall, wenn ein Objekt nicht wie erwartet erstellt wird, zeigt aber auch die Nützlichkeit eines leeren Catch
.
Es gibt ein zusätzliches Komma in der SQL (nach 'mailaddress'), was zu einer Ausnahme bei _.ExecuteReader
_ führt. Nachdem Catch
nichts unternommen hat, versucht Finally
, eine Bereinigung durchzuführen. Da Sie jedoch kein Close
-Null-Objekt DataReader
erstellen können, wird ein brandneues NullReferenceException
-Ergebnis angezeigt.
Ein leerer Catch
Block ist der Spielplatz des Teufels. Dieses OP war verblüfft, warum er ein NRE im Block Finally
bekam. In anderen Situationen kann ein leeres Catch
dazu führen, dass etwas anderes viel weiter stromabwärts verdrahtet wird und Sie Zeit damit verbringen, die falschen Dinge am falschen Ort nach dem Problem zu durchsuchen. (Die oben beschriebene "stille Ausnahme" bietet denselben 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 dienen nicht dazu, Ausnahmen vor der Person zu verbergen, die für deren Behebung ausschließlich qualifiziert ist - dem Entwickler.
_For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
_
Die Funktion IsDBNull
wird verwendet, um zu testen, ob ein Wert _System.DBNull
_: Von MSDN: entspricht
Der System.DBNull-Wert 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
...
_
FirstOrDefault
gibt das erste Element oder den Standardwert zurück, nämlich Nothing
für Referenztypen und niemals DBNull
:
_If getFoo IsNot Nothing Then...
_
_Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
_
Wenn ein CheckBox
mit chkName
nicht gefunden werden kann (oder in einem GroupBox
vorhanden ist), ist chk
Nothing und der Versuch, auf eine Eigenschaft zu verweisen, führt zu einer Ausnahme.
Abhilfe
_If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
_
Die DGV hat ein paar Macken in regelmäßigen Abständen zu sehen:
_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 dgvBooks
_AutoGenerateColumns = True
_ hat, werden die Spalten erstellt, jedoch nicht benannt, sodass der obige Code fehlschlägt, wenn auf sie namentlich verwiesen wird.
Abhilfe
Benennen Sie die Spalten manuell oder referenzieren Sie sie nach Index:
_dgvBooks.Columns(0).Visible = True
_
_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 Ihr DataGridView
AllowUserToAddRows
als True
hat (Standardeinstellung), enthält das Cells
in der leeren/neuen Zeile unten alle Nothing
. Die meisten Versuche, den Inhalt zu verwenden (z. B. ToString
), führen zu einem NRE.
Abhilfe
Verwenden Sie eine _For/Each
_-Schleife, und testen Sie die Eigenschaft IsNewRow
, um festzustellen, ob es sich um die letzte Zeile handelt. Dies funktioniert unabhängig davon, ob AllowUserToAddRows
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 n
_-Schleife verwenden, ändern Sie die Zeilenanzahl oder verwenden Sie _Exit For
_, wenn IsNewRow
wahr ist.
Unter bestimmten Umständen kann der Versuch, ein Element aus _My.Settings
_ zu verwenden, bei dem es sich um ein StringCollection
handelt, zu einer NullReference führen, wenn Sie es zum ersten Mal verwenden. Die Lösung ist die gleiche, 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 der Fall, 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 Nothing
, wenn im Einstellungseditor keine Elemente zum Hinzufügen vorhanden sind.
Abhilfe
Initialisieren Sie die Einstellungssammlung im Load
-Ereignishandler 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 Settings
-Auflistung nur beim ersten Ausführen der Anwendung initialisiert werden. Alternativ können Sie Ihrer Sammlung unterProjekt -> Einstellungen | einen Anfangswert hinzufügen FooBars, speichern Sie das Projekt und entfernen Sie den falschen Wert.
Sie haben wahrscheinlich den Operator New
vergessen.
oder
Etwas, von dem Sie angenommen haben, dass es fehlerfrei funktioniert, wenn ein initialisiertes Objekt an Ihren Code zurückgegeben wird, hat dies nicht getan.
Ignorieren Sie keine Compiler-Warnungen (jemals) und verwenden Sie _Option Strict On
_ (immer).
Ein anderes Szenario ist, wenn Sie ein Nullobjekt in ein Werttyp umwandeln. Zum Beispiel der folgende Code:
object o = null;
DateTime d = (DateTime)o;
Es wird ein NullReferenceException
auf die Besetzung werfen. In dem obigen Beispiel scheint dies ziemlich offensichtlich zu sein, aber dies kann in komplizierteren Szenarien mit "später Bindung" auftreten, 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 das folgende einfache ASP.NET-Bindungsfragment mit dem Calendar-Steuerelement:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Hier ist SelectedDate
tatsächlich eine Eigenschaft des Typs DateTime
des Typs Calendar
Web Control, und die Bindung könnte perfekterweise etwas Null zurückgeben. Der implizite ASP.NET-Generator erstellt einen Code, der dem obigen Umwandlungscode entspricht. Und dies wird ein NullReferenceException
erzeugen, das ziemlich schwer zu erkennen ist, da es in ASP.NET-generiertem Code liegt, der sich gut kompilieren lässt ...
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, da ich zwar die Variable "connection
" deklariert habe, sie aber nicht auf irgendetwas zeigt. Wenn ich versuche, das Member "Open
" aufzurufen, muss es nicht aufgelöst werden, und es wird den Fehler auslösen.
Um diesen Fehler zu vermeiden:
object == null
.Das JetBrains-Resharper-Tool erkennt jede Stelle in Ihrem Code, an der möglicherweise ein Null-Referenzfehler auftritt, und ermöglicht es Ihnen, eine Null-Überprüfung durchzuführen. Dieser Fehler ist die häufigste Fehlerquelle, IMHO.
Dies bedeutet, dass Ihr Code eine Objektreferenzvariable verwendet hat, die auf null gesetzt wurde (d. H., Dass sie nicht auf eine tatsächliche Objektinstanz verwiesen hat).
Um den Fehler zu vermeiden, sollten Objekte, die null sein könnten, vor der Verwendung auf null getestet werden.
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
Beachten Sie, dass die Ursache in .NET unabhängig vom Szenario immer dieselbe ist:
Sie versuchen, eine Referenzvariable zu verwenden, deren Wert
Nothing
/null
ist. Wenn der Wert für die ReferenzvariableNothing
/null
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 Sie haben die Variable manuell auf
Nothing
/null
gesetzt, oder Sie haben eine Funktion aufgerufen, mit der die Variable festgelegt wurde anNothing
/null
für Sie.
Ein Beispiel für diese Ausnahmebedingung lautet: 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, d. H. Für den obigen Code.
Im Vergleich zu einer ArgumentNullException, die normalerweise als defensive Maß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.
Update C # 8.0, 2019: Nullable reference types
C # 8.0 führt nullfähige Referenztypen und nicht nullfähige Referenztypen ein. Daher müssen nur nullfähige Referenztypen überprüft werden, um eine NullReferenceException zu vermeiden.
Wenn Sie einen Referenztyp nicht 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 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 zwischen Werttypen und [Referenztypen] [3] zu kennen.
Wenn Sie es also mit Werttypen zu tun haben, können NullReferenceExceptions nicht auftreten. Sie müssen jedoch im Umgang mit Referenztypen wachsam sein!
Nur Referenztypen können, wie der Name schon sagt, Referenzen enthalten oder wörtlich auf nichts verweisen (oder 'null'). Während Werttypen immer einen Wert enthalten.
Referenztypen (diese müssen überprüft werden):
Werttypen (Sie können diese einfach ignorieren):
Ein weiterer Fall, in dem NullReferenceExceptions
auftreten kann, ist die (falsche) Verwendung des Operators as
:
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 sind Book
und Car
inkompatible Typen. Ein Car
kann nicht in ein Book
konvertiert/umgewandelt werden. Wenn diese Umwandlung fehlschlägt, gibt as
null
zurück. Die anschließende Verwendung von mybook
führt zu einem NullReferenceException
.
Im Allgemeinen sollten Sie eine Besetzung oder as
wie folgt verwenden:
Wenn Sie erwarten, dass die Typkonvertierung immer erfolgreich ist (dh Sie wissen, was das Objekt vor der Zeit sein sollte), sollten Sie eine Umwandlung verwenden:
ComicBook cb = (ComicBook)specificBook;
Wenn Sie sich nicht sicher sind, aber den Typ try als bestimmten Typ verwenden möchten, verwenden Sie as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Sie verwenden das Objekt, das die Nullwertreferenz enthält. Es gibt also eine Null-Ausnahme. In diesem Beispiel ist der Zeichenfolgewert null, und bei der Überprüfung der 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: Der Objektverweis wurde nicht auf eine Instanz eines Objekts festgelegt. bei Program.Main ()
Während , was eine NullReferenceExceptions und Ansätze zu vermeiden/fix Eine solche Ausnahme wurde in anderen Antworten angesprochen. Was viele Programmierer noch nicht gelernt haben, ist, wie sie solche Ausnahmen während der Entwicklung unabhängig debuggen .
In Visual Studio ist dies normalerweise dank des Visual Studio Debugger einfach.
Stellen Sie zunächst sicher, dass der richtige Fehler abgefangen wird - siehe Wie kann ich zulassen, dass 'System.NullReferenceException' in VS2010 unterbrochen wird? Hinweis1
Dann entweder Start with Debugging (F5) oder Attach [the VS Debugger] zu Running Process . Gelegentlich kann es nützlich sein, Debugger.Break
zu verwenden, um den Debugger zu starten.
Wenn die NullReferenceException ausgelöst (oder nicht behandelt) wird, stoppt der Debugger in der Zeile, in der die Ausnahme aufgetreten ist (beachten Sie die oben festgelegte Regel?). Manchmal ist der Fehler leicht zu erkennen.
In der folgenden Zeile ist beispielsweise der einzige Code, der die Ausnahme verursachen kann , wenn myString
den Wert null hat. Dies kann durch Betrachten des Watch Window oder Ausführen von Ausdrücken im Immediate Window überprüft werden.
_var x = myString.Trim();
_
In fortgeschritteneren Fällen, wie z. B. den folgenden, müssen Sie eine der oben genannten Techniken (Überwachen oder Sofortiges Windows) verwenden, um die Ausdrücke zu überprüfen und festzustellen, ob _str1
_ null war oder ob _str2
_ null war .
_var x = str1.Trim() + str2.Trim();
_
Sobald wo die Ausnahme gefunden wurde, ist es normalerweise trivial, rückwärts zu argumentieren, um herauszufinden, wo der Nullwert [falsch] eingeführt wurde -
Nehmen Sie sich die Zeit, um die Ursache der Ausnahme zu verstehen. Untersuchen Sie auf Null-Ausdrücke. Überprüfen Sie die vorherigen Ausdrücke, die zu solchen Null-Ausdrücken hätten führen können. Fügen Sie Haltepunkte hinzu und führen Sie die entsprechenden Schritte 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 erfassten Ausnahmen zu begrenzen. Zusätzlich führt VS2012 Just My Code ein, das ich ebenfalls empfehlen würde.
Wenn Sie das Debuggen mit aktivierter Option "Nur mein Code" ausführen, ist das Verhalten etwas anders. Wenn "Nur mein Code" aktiviert ist, ignoriert der Debugger CLR-Ausnahmen (Common Language Runtime) der ersten Chance, die außerhalb von "Mein Code" ausgelöst werden und nicht über "Mein Code" übertragen werden
Simon Mourier gab dieses Beispiel :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
wobei eine Unboxing Konvertierung (Besetzung) von object
(oder aus einer der Klassen System.ValueType
oder System.Enum
oder aus einem Schnittstellentyp) bis einen Werttyp (außer Nullable<>
) an sich gibt den NullReferenceException
.
In der anderen Richtung ergibt sich eine Boxen Konvertierung von Ein Nullable<>
, der HasValue
gleich false
zu einem Referenztyp hat, kann einen null
-Referenz geben, der dann kann später zu einem NullReferenceException
führen. 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 wird problematisch sein:
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.
Hinzufügen eines Falls, bei dem der Klassenname für die in Entity Framework verwendete Entität mit dem Klassennamen für eine CodeBehind-Datei für Webformulare 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 die Entität und die Codebehind-Klasse im gleichen Namespace befinden. Benennen Sie die Entitätsklasse oder die Codebehind-Klasse für Contact.aspx um, um das zu beheben.
Grund Ich bin mir immer noch nicht sicher über den Grund. Dieser Fehler tritt jedoch immer dann auf, wenn eine der Entitätsklassen System.Web.UI.Page erweitert.
Zur Diskussion schauen Sie sich NullReferenceException in DbContext.saveChanges () an
Ein weiterer allgemeiner Fall, in dem diese Ausnahme auftreten kann, ist das Verspotten von Klassen während des Komponententests. Unabhängig davon, welches Mock-Framework verwendet wird, müssen Sie sicherstellen, dass alle geeigneten Ebenen der Klassenhierarchie ordnungsgemäß verspottet sind. Insbesondere müssen alle Eigenschaften von HttpContext
, auf die der zu testende Code verweist, verspottet werden.
Ein etwas ausführliches Beispiel finden Sie unter " NullReferenceException ausgelöst beim Testen von benutzerdefiniertem AuthorizationAttribute ".
Ich habe eine andere Perspektive, um darauf zu antworten. Diese Art von Antworten "Was kann ich noch tun, um dies zu vermeiden?"
Wenn Sie über mehrere Ebenen hinweg arbeiten, beispielsweise in einer MVC-Anwendung, benötigt ein Controller Dienste, um Geschäftsvorgänge aufzurufen. In solchen Szenarien kann Dependency Injection Container verwendet werden, um die Dienste zu initialisieren und die NullReferenceException zu vermeiden. Das bedeutet, dass Sie sich keine Gedanken über das Überprüfen auf Null machen müssen und die Dienste nur 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();
}
}
In Bezug auf "Was soll ich dagegen tun" kann es viele Antworten geben.
Eine "formalere" Möglichkeit, solche Fehlerzuständewährend der Entwicklung zu verhindern, besteht darin,Design by Contractin Ihrem Code. Das heißt, Sie müssen die Klasseinvariantsund/oder sogar die Funktion/methodpreconditionsundpostconditionsauf Ihrem System während der Entwicklung.
Kurz gesagt,Klasseninvariantenstellen sicher, dass es in Ihrer Klasse einige Einschränkungen gibt, die bei normaler Verwendung nicht verletzt werden (und daher wird die Klassenotin einen inkonsistenten Zustand geraten).Vorbedingungenbedeutet, dass Daten, die als Eingabe für eine Funktion/Methode angegeben werden, bestimmten Einschränkungen folgen müssen und nie sie verletzen müssen, undpostconditionsbedeutet, dass eine Funktions-/Methodenausgabe den festgelegten Einschränkungen erneut folgen muss, ohne sie jemals zu verletzen. Die Vertragsbedingungen sollten nie während der Ausführung eines fehlerfreien Programms verletzt werden, daher wird das vertragliche Design in der Praxis im Debug-Modus überprüft, während in Releasesdeaktiviert ist, um die Leistung des entwickelten Systems zu maximieren.
Auf diese Weise können Sie NullReferenceException
Fälle vermeiden, die auf eine Verletzung der festgelegten Einschränkungen zurückzuführen sind. Wenn Sie beispielsweise eine Objekteigenschaft X
in einer Klasse verwenden und später versuchen, eine ihrer Methoden aufzurufen, und X
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 "Eigenschaft X darf niemals einen Nullwert haben" als Methodenvoraussetzung festlegen, können Sie das zuvor beschriebene Szenario verhindern:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Aus diesem Grund ist für .NET-AnwendungenCode Contractsproject vorhanden.
Alternativ kann Design by Contract mitZusicherungenangewendet werden.
PDATE: Erwähnenswert ist, dass der Begriff von Bertrand Meyer geprägt wurde im Zusammenhang mit seinem Entwurf der Programmiersprache Eiffel .
Ein NullReferenceException
wird ausgelöst, wenn versucht wird, auf Eigenschaften eines Nullobjekts zuzugreifen, oder wenn ein Zeichenfolgenwert leer wird und versucht wird, auf Zeichenfolgenmethoden zuzugreifen.
Zum Beispiel:
Wenn auf eine Zeichenfolgemethode einer leeren Zeichenfolge zugegriffen wird:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Wenn auf eine Eigenschaft eines Nullobjekts zugegriffen wird:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
TL; DR: Versuchen Sie, Html.Partial
anstelle von Renderpage
zu verwenden.
Ich habe Object reference not set to an instance of an object
erhalten, als ich versucht habe, eine Ansicht in einer Ansicht zu rendern, indem ich ihr ein Modell 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 in:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
Und es hat funktioniert.
Der Grund, warum ich Html.Partial
nicht hatte, war, dass Visual Studio manchmal fehlerhaft aussehende verschnörkelte Linien unter Html.Partial
wirft, wenn es sich in einer anders konstruierten foreach
-Schleife 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 beheben, indem ich die Struktur der foreach
-Schleife so änderte, dass sie wie folgt aussah:
@foreach(var M in MyEntities){
...
}
Obwohl ich das Gefühl habe, dass Visual Studio das kaufmännische Und und die eckigen Klammern falsch interpretiert hat.
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, das Problem zu verhindern oder es zumindest einfacher zu machen, es zu fangen.
Argumente prüfen
Beispielsweise können Methoden die verschiedenen Argumente überprüfen, um festzustellen, ob sie null sind, und eine ArgumentNullException
auslösen, eine Ausnahme, die offensichtlich genau für diesen Zweck erstellt wurde.
Der Konstruktor für ArgumentNullException
verwendet sogar den Namen des Parameters und eine Nachricht als Argumente, damit Sie dem Entwickler genau mitteilen können, um welches Problem es sich handelt.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Tools verwenden
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 Contract.Requires(obj != null)
verwenden, mit der Sie die Laufzeit und Kompilierung überprüfen können: Introducing Code Contracts .
Es gibt auch "PostSharp", mit dem Sie Attribute wie diese verwenden können:
public void DoSometing([NotNull] obj)
Auf diese Weise wird obj
zur Laufzeit auf null überprüft, damit PostSharp Teil Ihres Build-Prozesses wird. Siehe: PostSharp null check
Plain Code Solution
Oder Sie können Ihren eigenen Ansatz immer mit einfachem altem Code codieren. Hier ist beispielsweise eine Struktur, mit der Sie Nullreferenzen abfangen können. Es ist nach dem gleichen Konzept wie Nullable<T>
modelliert:
[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 verwenden wie Nullable<T>
, außer mit dem Ziel, genau das Gegenteil zu erreichen - null
nicht zuzulassen. 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 in und aus T
umgewandelt, sodass Sie es praktisch überall verwenden können, wo Sie es benötigen. Beispielsweise können Sie ein Person
-Objekt an eine Methode übergeben, die einen NotNull<Person>
annimmt:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Wie Sie oben sehen können, würden Sie wie bei nullable über die Eigenschaft Value
auf den zugrunde liegenden Wert zugreifen. Alternativ können Sie eine explizite oder implizite Umwandlung verwenden. Nachfolgend sehen Sie ein Beispiel mit dem Rückgabewert:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Sie können es auch verwenden, wenn die Methode nur T
(in diesem Fall Person
) zurückgibt, indem Sie eine Umwandlung durchführen. Der folgende Code würde beispielsweise den obigen Code genau mögen:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Mit Erweiterung kombinieren
Wenn Sie NotNull<T>
mit einer Erweiterungsmethode kombinieren, können Sie 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 null
ist, gibt der gesamte Ausdruck null
zurück.
Dies reduziert die Anzahl der Nullprüfungen, die Sie in einigen Fällen durchführen müssen. Die Syntax besteht darin, vor jeden Punkt ein Fragezeichen zu setzen. Nehmen Sie zum Beispiel den folgenden Code:
var address = country?.State?.County?.City;
Stellen Sie sich vor, country
ist ein Objekt vom Typ Country
mit der Eigenschaft State
und so weiter. Wenn country
, State
, County
oder City
null
ist, dann address will be
null. Therefore you only have to check whether
addressis
null`.
Es ist eine großartige Funktion, aber es gibt Ihnen weniger Informationen. Es ist nicht ersichtlich, 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 nach dem Typ ein Fragezeichen setzen wie int?
.
Es wäre schön, wenn C # so etwas wie die obige NotNull<T>
-Struktur und eine ähnliche Kurzform hätte, vielleicht das Ausrufezeichen (!), Damit Sie so etwas schreiben könnten wie: public void WriteName(Person! person)
.
Sie können NullReferenceException auf saubere Weise mit 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 Elementzugriffs ?.) 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: --- (Null-Bedingungsoperatoren
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: Nehmen wir an, Sie haben eine Klasse namens myClass und sie enthält eine Eigenschaft prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Jetzt greifen Sie auf dieses prop1 in einer anderen Klasse wie unten 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;
}
}
Interessanterweise erwähnt keine der Antworten auf dieser Seite die beiden Edge-Fälle. Hoffe, dass es niemanden stört, wenn ich sie hinzufüge:
Generische Wörterbücher in .NET sind nicht threadsicher und können manchmal ein NullReference
oder sogar (häufiger) ein KeyNotFoundException
auslösen, wenn Sie versuchen, von zwei gleichzeitig auf einen Schlüssel zuzugreifen Fäden. Die Ausnahme ist in diesem Fall ziemlich irreführend.
Wenn ein NullReferenceException
durch unsafe
Code ausgelöst wird, können Sie Ihre Zeigervariablen überprüfen und sie auf IntPtr.Zero
oder etwas anderes überprüfen. Das ist dasselbe ("Nullzeiger-Ausnahme"), aber in unsicherem Code werden Variablen häufig in Werttypen/Arrays usw. umgewandelt, und Sie stoßen mit dem Kopf gegen die Wand und fragen sich, wie ein Werttyp dies auslösen kann Ausnahme.
(Ein weiterer Grund, warum Sie unsicheren Code nicht verwenden, es sei denn, Sie benötigen ihn.)
Eine 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 mit dem Namen 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 also die Anweisung s.GetFullName () ausgeführt wird, wird die NullReferenceException ausgelöst.
Nun, in einfachen Worten:
Sie versuchen, auf ein Objekt zuzugreifen, das nicht erstellt wurde oder sich derzeit nicht im Speicher befindet.
So gehen Sie vor:
Debuggen und den Debugger unterbrechen lassen ... Sie werden direkt zu der fehlerhaften Variablen weitergeleitet ... Jetzt müssen Sie das einfach beheben. Verwenden Sie das neue Schlüsselwort in der geeignete Ort.
Wenn es bei einigen Datenbankbefehlen auftritt, weil das Objekt nicht vorhanden ist, müssen Sie nur eine Nullprüfung durchführen und damit umgehen:
if (i == null) {
// Handle this
}
Das Schwierigste .. wenn GC das Objekt bereits gesammelt hat ... Dies tritt im Allgemeinen auf, wenn Sie versuchen, ein Objekt mithilfe von Zeichenfolgen zu finden. .. Das heißt, wenn Sie es nach dem Namen des Objekts suchen, kann es vorkommen, dass der GC es bereits bereinigt hat. Dies ist schwer zu finden und wird zu einem ziemlichen Problem Überprüfungen, wo immer dies während des Entwicklungsprozesses erforderlich ist. So sparen Sie viel Zeit.
Mit dem Suchen nach Namen meine ich, dass einige Frameworks es Ihnen ermöglichen, Objekte mithilfe von Zeichenfolgen zu finden, und der Code könnte folgendermaßen aussehen: FindObject ("ObjectName");
Es gibt zwei Möglichkeiten, um eine NullReferenceExeption im wahrsten Sinne des Wortes zu beheben. Wenn Sie beispielsweise ein GameObject mit einem angehängten Skript und einer Variablen mit dem Namen rb (starrer Körper) haben, wird diese Variable beim Starten des Spiels mit null beginnen.
Aus diesem Grund erhalten Sie eine NullReferenceExeption, da auf dem Computer keine Daten in dieser Variablen gespeichert sind.
Als Beispiel verwende ich eine RigidBody-Variable.
Wir können Daten auf verschiedene Arten ganz einfach hinzufügen:
rb = GetComponent<Rigidbody>();
Start()
oder Awake()
.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 eingeben (das Leerzeichen unter allen Ihren Verwendungen).
Viel Spaß beim Spielen!
Wenn wir allgemeine Szenarien betrachten, in denen diese Ausnahme ausgelöst werden kann, greifen Sie auf Eigenschaften zu, wobei sich das Objekt oben befindet.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
wenn die Adresse hier null ist, erhalten Sie eine NullReferenceException.
In der Praxis sollten wir daher immer die Nullprüfung verwenden, bevor wir auf Eigenschaften in solchen Objekten zugreifen (insbesondere in generischen Objekten).
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception