Ho un po 'di codice e quando viene eseguito, genera un NullReferenceException
, dicendo:
Il riferimento non impostato su un'istanza di un oggetto.
Che cosa significa questo e cosa posso fare per correggere questo errore?
Ho un po 'di codice e quando viene eseguito, genera un NullReferenceException
, dicendo:
Il riferimento non impostato su un'istanza di un oggetto.
Che cosa significa questo e cosa posso fare per correggere questo errore?
Risposte:
Stai tentando di utilizzare qualcosa che è null
(o Nothing
in VB.NET). Questo significa che l'hai impostato su null
o non l'hai mai impostato su niente.
Come ogni altra cosa, null
viene passato in giro. Se è null
in modalità "A", potrebbe essere che il metodo "B" ha approvato una null
al metodo di "A".
null
può avere significati diversi:
NullReferenceException
.null
intenzionalmente per indicare che non è disponibile alcun valore significativo. Si noti che C # ha il concetto di tipi di dati nullable per le variabili (come le tabelle del database possono avere campi nullable) - è possibile assegnare null
loro per indicare che non vi è alcun valore memorizzato in esso, ad esempio int? a = null;
dove il punto interrogativo indica che è consentito archiviare null in variabile a
. Puoi verificarlo con if (a.HasValue) {...}
o con if (a==null) {...}
. Le variabili nullable, come in a
questo esempio, consentono di accedere al valore in modo a.Value
esplicito o altrettanto normale tramite a
. a.Value
genera InvalidOperationException
invece di una NullReferenceException
, se a
non è innull
- dovresti fare il controllo in anticipo, cioè se hai un'altra variabile annullabile, int b;
allora dovresti fare incarichi simili if (a.HasValue) { b = a.Value; }
o più brevi if (a != null) { b = a; }
.Il resto di questo articolo approfondisce e mostra gli errori che molti programmatori fanno spesso che possono portare a NullReferenceException
.
Il runtime
gettando un NullReferenceException
sempre significa la stessa cosa: si sta tentando di usare un riferimento, e il riferimento non è inizializzata (o era una volta inizializzato, ma è non è più inizializzato).
Ciò significa che il riferimento è null
e non è possibile accedere ai membri (come i metodi) tramite un null
riferimento. Il caso più semplice:
string foo = null;
foo.ToUpper();
Questo lancerà NullReferenceException
a sulla seconda riga perché non puoi chiamare il metodo di istanza ToUpper()
su un string
riferimento che punta a null
.
Come trovi la fonte di un NullReferenceException
? Oltre a guardare l'eccezione stessa, che verrà generata esattamente nella posizione in cui si verifica, si applicano le regole generali di debug in Visual Studio: posizionare punti di interruzione strategici e ispezionare le variabili , passando il mouse sui loro nomi, aprendo un ( Veloce) Guarda la finestra o usando i vari pannelli di debug come Locali e Auto.
Se vuoi scoprire dove si trova o non è impostato il riferimento, fai clic con il pulsante destro del mouse sul nome e seleziona "Trova tutti i riferimenti". È quindi possibile posizionare un punto di interruzione in ogni posizione trovata ed eseguire il programma con il debugger collegato. Ogni volta che il debugger si interrompe su un tale punto di interruzione, è necessario determinare se si prevede che il riferimento sia non nullo, ispezionare la variabile e verificare che punti a un'istanza quando previsto.
Seguendo il flusso del programma in questo modo, è possibile trovare la posizione in cui l'istanza non deve essere nulla e perché non è impostata correttamente.
Alcuni scenari comuni in cui è possibile generare l'eccezione:
ref1.ref2.ref3.member
Se ref1 o ref2 o ref3 sono nulli, otterrai a NullReferenceException
. Se vuoi risolvere il problema, scopri quale è nullo riscrivendo l'espressione nel suo equivalente più semplice:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
In particolare, in HttpContext.Current.User.Identity.Name
, HttpContext.Current
potrebbe essere nullo oppure la User
proprietà potrebbe essere nulla oppure la Identity
proprietà potrebbe essere nulla.
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.
}
}
Se si desidera evitare il riferimento null figlio (Persona), è possibile inizializzarlo nel costruttore dell'oggetto genitore (Libro).
Lo stesso vale per gli inizializzatori di oggetti nidificati:
Book b1 = new Book
{
Author = { Age = 45 }
};
Questo si traduce in
Book b1 = new Book();
b1.Author.Age = 45;
Mentre la new
parola chiave viene utilizzata, crea solo una nuova istanza di Book
, ma non una nuova istanza di Person
, quindi Author
la proprietà è ferma null
.
public class Person
{
public ICollection<Book> Books { get; set; }
}
public class Book
{
public string Title { get; set; }
}
La raccolta nidificata si Initializers
comporta allo stesso modo:
Person p1 = new Person
{
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Questo si traduce in
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
L' new Person
unico crea un'istanza di Person
, ma la Books
raccolta è ancora null
. La Initializer
sintassi della raccolta non crea una raccolta per p1.Books
, si traduce solo nelle p1.Books.Add(...)
istruzioni.
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
}
}
###Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
public class Form1 {cliente privato del cliente;
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);
}
}
Questo può essere risolto seguendo la convenzione per aggiungere un prefisso ai campi con un trattino basso:
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();
Se l'eccezione si verifica quando si fa riferimento a una proprietà di @Model
in ASP.NET MVC View
, è necessario comprendere che Model
viene impostato nel metodo di azione, quando si return
visualizza. Quando si restituisce un modello vuoto (o proprietà del modello) dal controller, l'eccezione si verifica quando le viste accedono ad esso:
// 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
i controlli vengono creati durante la chiamata a InitializeComponent
nell'ordine in cui compaiono nell'albero visivo. A NullReferenceException
verrà generato nel caso di controlli creati in anticipo con gestori di eventi, ecc., Quell'incendio durante il InitializeComponent
quale i controlli creati in ritardo di riferimento.
Per esempio :
<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>
Qui comboBox1
è stato creato prima label1
. Se comboBox1_SelectionChanged
tenta di fare riferimento a `label1, non sarà ancora stato creato.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Cambiare l'ordine delle dichiarazioni nel XAML
(cioè, elencare label1
prima comboBox1
, ignorare le questioni della filosofia del design, risolverebbe almeno il NullReferenceException
qui.
as
var myThing = someObject as Thing;
Questo non genera un InvalidCastException
ma restituisce un null
errore quando il cast fallisce (e quando someObject
è nullo). Quindi sii consapevole di ciò.
FirstOrDefault()
eSingleOrDefault()
Le versioni semplici First()
e Single()
generano eccezioni quando non c'è nulla. Le versioni "OrDefault" restituiscono null in quel caso. Quindi sii consapevole di ciò.
foreach
genera quando si tenta di ripetere la raccolta null. Generalmente causato da null
risultati imprevisti da metodi che restituiscono raccolte.
List<int> list = null;
foreach(var v in list) { } // exception
Esempio più realistico: selezionare i nodi dal documento XML. Verrà generato se i nodi non vengono trovati ma il debug iniziale mostra che tutte le proprietà sono valide:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
e ignorare i valori null.Se a volte ti aspetti che il riferimento sia nullo, puoi verificarne la presenza null
prima di accedere ai membri dell'istanza:
void PrintName(Person p)
{
if (p != null)
{
Console.WriteLine(p.Name);
}
}
null
e fornire un valore predefinito.I metodi che ti aspetti di restituire possono restituire un'istanza null
, ad esempio quando non è possibile trovare l'oggetto da cercare. Puoi scegliere di restituire un valore predefinito in questo caso:
string GetCategory(Book b)
{
if (b == null)
return "Unknown";
return b.Category;
}
null
chiamate di metodo e genera un'eccezione personalizzata.Puoi anche generare un'eccezione personalizzata, solo per catturarla nel codice chiamante:
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
se un valore non dovrebbe mai essere null
, per rilevare il problema prima che si verifichi l'eccezione.Quando sai durante lo sviluppo che un metodo può, ma non dovrebbe mai tornare null
, puoi usare Debug.Assert()
per interrompere il più presto possibile quando si verifica:
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.
}
Sebbene questo controllo non finisca nella build di rilascio , causando il lancio di NullReferenceException
nuovo quando book == null
in fase di esecuzione in modalità di rilascio.
GetValueOrDefault()
per i nullable
tipi di valore per fornire un valore predefinito quando lo sono 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
??
[C #] o If()
[VB].La scorciatoia per fornire un valore predefinito quando null
viene rilevato un:
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;
}
?.
o ?[x]
per array (disponibile in C # 6 e VB.NET 14):Questo è talvolta chiamato anche navigazione sicura o Elvis (dopo la sua forma) operatore. Se l'espressione sul lato sinistro dell'operatore è null, il lato destro non verrà valutato e verrà invece restituito null. Ciò significa casi come questo:
var title = person.Title.ToUpper();
Se la persona non ha un titolo, ciò genererà un'eccezione perché sta provando a chiamare ToUpper
una proprietà con un valore nullo.
In C# 5
e sotto, questo può essere protetto con:
var title = person.Title == null ? null : person.Title.ToUpper();
Ora la variabile del titolo sarà nulla invece di generare un'eccezione. C # 6 introduce una sintassi più breve per questo:
var title = person.Title?.ToUpper();
Ciò comporterà la variabile del titolo essendo null
, e la chiamata a ToUpper
non viene effettuata se lo person.Title
è null
.
Ovviamente, devi ancora verificare la presenza title
di null o utilizzare l'operatore condizione null insieme all'operatore null coalescing ( ??
) per fornire un valore predefinito:
// 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;
Allo stesso modo, per gli array è possibile utilizzare ?[i]
come segue:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Questo farà quanto segue: Se myIntArray
è null, l'espressione restituisce null e puoi verificarla in sicurezza. Se contiene un array, farà lo stesso di:
elem = myIntArray[i];
e restituisce l' i<sup>th</sup>
elemento.
Introdotti in C# 8
questo contesto, i tipi di riferimento null e nullble eseguono analisi statiche sulle variabili e forniscono un avviso del compilatore se un valore può essere potenzialmente nullo o se è stato impostato su null. I tipi di riferimento nullable consentono ai tipi di essere esplicitamente autorizzati a essere nulli.
Il contesto di annotazione nullable e il contesto di avviso nullable possono essere impostati per un progetto usando l' Nullable
elemento nel csproj
file. Questo elemento configura il modo in cui il compilatore interpreta la nullità dei tipi e quali avvisi vengono generati. Le impostazioni valide sono:
Un tipo di riferimento nullable viene notato usando la stessa sintassi dei tipi di valore nullable: a ?
viene aggiunto al tipo di variabile.
C#
supporta "blocchi iteratori" (chiamati "generatori" in alcune altre lingue popolari). Le eccezioni di dereferenza nulla possono essere particolarmente difficili da eseguire il debug nei blocchi iteratori a causa dell'esecuzione differita:
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) { ... }
Se i whatever
risultati null
entrano, MakeFrob
verranno lanciati. Ora, potresti pensare che la cosa giusta da fare sia questa:
// 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();
}
Perché è sbagliato? Perché il blocco iteratore non viene eseguito fino a quando foreach
! La chiamata a GetFrobs
restituisce semplicemente un oggetto che una volta eseguito eseguirà il blocco iteratore.
Scrivendo un controllo null come questo si impedisce la dereferenza null, ma si sposta l'eccezione dell'argomento null sul punto dell'iterazione , non sul punto della chiamata , e questo è molto confuso per il debug .
La correzione corretta è:
// 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();
}
Ossia, crea un metodo di supporto privato con la logica del blocco iteratore e un metodo di superficie pubblica che esegua il controllo null e restituisca l'iteratore. Ora, quando GetFrobs
viene chiamato, il controllo null GetFrobsForReal
viene eseguito immediatamente e quindi viene eseguito quando la sequenza viene ripetuta.
Se si esamina l'origine di riferimento per gli LINQ
oggetti, si vedrà che questa tecnica è utilizzata dappertutto. Scrivere è leggermente più ingombrante, ma semplifica notevolmente il debug degli errori di nullità. Ottimizza il tuo codice per la comodità del chiamante, non per la comodità dell'autore .
C#
ha una modalità "non sicura" che è, come suggerisce il nome, estremamente pericolosa perché i normali meccanismi di sicurezza che forniscono la sicurezza della memoria e la sicurezza del tipo non sono applicati. Non dovresti scrivere codice non sicuro a meno che tu non abbia una conoscenza approfondita e profonda di come funziona la memoria .
In modalità non sicura, è necessario essere consapevoli di due fatti importanti:
Per capire perché, aiuta in primo luogo a capire come .NET produce eccezioni di dereference nulle. (Questi dettagli si applicano a .NET in esecuzione su Windows; altri sistemi operativi utilizzano meccanismi simili.)
La memoria è virtualizzata in Windows
; ogni processo ottiene uno spazio di memoria virtuale di molte "pagine" di memoria che vengono monitorate dal sistema operativo. Su ogni pagina di memoria sono presenti dei flag che determinano il modo in cui può essere utilizzato: letto, scritto, eseguito e così via. La pagina più bassa è contrassegnata come "produce un errore se mai usata in alcun modo".
Sia un puntatore null che un riferimento null in C#
sono rappresentati internamente come il numero zero e quindi qualsiasi tentativo di dereferenziarlo nella sua memoria di archiviazione corrispondente provoca un errore nel sistema operativo. Il runtime .NET rileva quindi questo errore e lo trasforma nell'eccezione di dereference nulla.
Ecco perché la dereferenziazione sia di un puntatore null che di un riferimento null produce la stessa eccezione.
E il secondo punto? Dereferenziare qualsiasi puntatore non valido che cade nella pagina più bassa della memoria virtuale provoca lo stesso errore del sistema operativo e quindi la stessa eccezione.
Perché questo ha senso? Bene, supponiamo di avere una struttura contenente due ints e un puntatore non gestito uguale a null. Se tentiamo di dereferenziare il secondo int nella struttura, CLR
non tenterà di accedere alla memoria nella posizione zero; accederà alla memoria nella posizione quattro. Ma logicamente questa è una nullità perché stiamo arrivando a quell'indirizzo tramite il null.
Se stai lavorando con un codice non sicuro e ricevi un'eccezione di dereference nulla, tieni presente che il puntatore offensivo non deve essere null. Può essere qualsiasi posizione nella pagina più bassa e verrà prodotta questa eccezione.
new Book { Author = { Age = 45 } };
In che modo anche l'inizializzazione interiore ... Non riesco a pensare a una situazione in cui l'init interiore avrebbe mai funzionato, ma si compila e l'intellisense funziona ... A meno che per le strutture?
Il NullReference Exception
per Visual Basic non è diverso da quello in C # . Dopotutto, entrambi segnalano la stessa eccezione definita in .NET Framework che utilizzano entrambi. Le cause uniche di Visual Basic sono rare (forse solo una).
Questa risposta utilizzerà i termini, la sintassi e il contesto di Visual Basic. Gli esempi utilizzati provengono da un gran numero di precedenti domande di overflow dello stack. Questo per massimizzare la pertinenza usando i tipi di situazioni spesso visti nei post. Una spiegazione in più è fornita anche per coloro che potrebbero averne bisogno. Un esempio simile al tuo è molto probabilmente elencato qui.
Nota:
NullReferenceException
(NRE), come trovarlo, come risolverlo e come evitarlo. Un NRE può essere causato in molti modi, quindi è improbabile che questo sia il tuo unico incontro.Il messaggio "Oggetto non impostato su un'istanza di Oggetto" indica che si sta tentando di utilizzare un oggetto che non è stato inizializzato. Questo si riduce a uno di questi:
Poiché il problema è un riferimento a un oggetto Nothing
, la risposta è esaminarli per scoprire quale. Quindi determinare perché non è inizializzato. Tieni il mouse sulle varie variabili e Visual Studio (VS) mostrerà i loro valori - il colpevole sarà Nothing
.
È inoltre necessario rimuovere eventuali blocchi Try / Catch dal codice pertinente, in particolare quelli in cui non è presente nulla nel blocco Catch. Ciò causerà l'arresto anomalo del codice quando tenta di utilizzare un oggetto che lo è Nothing
. Questo è quello che vuoi perché identificherà la posizione esatta del problema e ti permetterà di identificare l'oggetto che lo causa.
A MsgBox
nella cattura che viene visualizzato Error while...
sarà di scarso aiuto. Questo metodo porta anche a pessime domande su Stack Overflow, poiché non è possibile descrivere l'eccezione effettiva, l'oggetto coinvolto o persino la riga di codice in cui si verifica.
Puoi anche usare Locals Window
( Debug -> Windows -> Locals ) per esaminare i tuoi oggetti.
Una volta che sai qual è e dove si trova il problema, di solito è abbastanza facile da risolvere e più veloce di pubblicare una nuova domanda.
Guarda anche:
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Il problema è che Dim
non crea un oggetto CashRegister ; dichiara solo una variabile denominata reg
di quel tipo. Dichiarare una variabile oggetto e creare un'istanza sono due cose diverse.
Rimedio
L' New
operatore può spesso essere utilizzato per creare l'istanza quando viene dichiarata:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
Quando è appropriato creare l'istanza in un secondo momento:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Nota: Non utilizzare Dim
di nuovo in una procedura, compreso il costruttore ( Sub New
):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
Questo creerà una variabile localereg
, che esiste solo in quel contesto (sotto). La reg
variabile a livello di modulo Scope
che verrà utilizzato resti in qualsiasi altro luogo Nothing
.
L'
New
operatore mancante è la causa numero 1 delleNullReference Exceptions
domande di overflow dello stack esaminate.Visual Basic tenta di chiarire ripetutamente il processo utilizzando
New
: L'New
operatore crea un nuovo oggetto e chiamaSub New
- il costruttore - dove l'oggetto può eseguire qualsiasi altra inizializzazione.
Per essere chiari, Dim
(o Private
) dichiara solo una variabile e la sua Type
. L' ambito della variabile, indipendentemente dal fatto che esista per l'intero modulo / classe o sia locale in una procedura, è determinato da dove viene dichiarato. Private | Friend | Public
definisce il livello di accesso, non Scope .
Per ulteriori informazioni, vedere:
Le matrici devono inoltre essere istanziate:
Private arr as String()
Questo array è stato solo dichiarato, non creato. Esistono diversi modi per inizializzare un array:
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) {}
Nota: a partire da VS 2010, quando si inizializza un array locale usando un valore letterale e Option Infer
, gli elementi As <Type>
e New
sono facoltativi:
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}
Il tipo di dati e la dimensione dell'array sono dedotti dai dati assegnati. Le dichiarazioni a livello di classe / modulo richiedono ancora As <Type>
con Option Strict
:
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Esempio: matrice di oggetti di classe
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
L'array è stato creato, ma gli Foo
oggetti al suo interno no.
Rimedio
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
L'uso di a List(Of T)
renderà abbastanza difficile avere un elemento senza un oggetto valido:
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
Per ulteriori informazioni, vedere:
Anche le raccolte .NET (di cui esistono molte varietà - Elenchi, Dizionario, ecc.) Devono essere istanziate o create.
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
Ottieni la stessa eccezione per lo stesso motivo: è myList
stata dichiarata solo, ma non è stata creata alcuna istanza. Il rimedio è lo stesso:
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
Una svista comune è una classe che utilizza una raccolta 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
Entrambe le procedure si tradurranno in un NRE, poiché barList
viene solo dichiarato, non istanziato. La creazione di un'istanza di Foo
non creerà anche un'istanza dell'interno barList
. Potrebbe essere stato l'intento di farlo nel costruttore:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
Come prima, questo non è corretto:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Per ulteriori informazioni, vedere List(Of T)
Classe .
Lavorare con i database presenta molte opportunità per una NullReference perché ci possono essere molti oggetti ( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) in uso in una sola volta. Nota: non importa quale fornitore di dati stai usando - MySQL, SQL Server, OleDB, ecc. - i concetti sono gli stessi.
Esempio 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
Come prima, l' ds
oggetto Dataset è stato dichiarato, ma non è mai stata creata un'istanza. Il DataAdapter
riempirà uno esistente DataSet
, non crearne uno. In questo caso, poiché ds
è una variabile locale, l'IDE ti avverte che ciò potrebbe accadere:
Se dichiarato come variabile a livello di modulo / classe, come sembra essere il caso con
, il compilatore non può sapere se l'oggetto è stato creato da una procedura a monte. Non ignorare gli avvisi.
Rimedio
Dim ds As New DataSet
Esempio 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)
Un errore di battitura è un problema qui: Employees
vs Employee
. Non è stato DataTable
creato alcun nome "Dipendente", quindi i NullReferenceException
risultati provano ad accedervi. Un altro potenziale problema sta presumendo Items
che potrebbe non esserlo quando l'SQL include una clausola WHERE.
Rimedio
Poiché utilizza una tabella, l'utilizzo Tables(0)
eviterà errori di ortografia. L'esame Rows.Count
può anche aiutare:
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
è una funzione che restituisce il numero di Rows
interessati che può anche essere testato:
If da.Fill(ds, "Employees") > 0 Then...
Esempio 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
Il DataAdapter
fornirà TableNames
come mostrato nell'esempio precedente, ma non è così i nomi di parsing dalla tabella SQL o database. Di conseguenza, fa ds.Tables("TICKET_RESERVATION")
riferimento a una tabella inesistente.
Il rimedio è lo stesso, fare riferimento alla tabella per indice:
If ds.Tables(0).Rows.Count > 0 Then
Vedi anche Classe DataTable .
If myFoo.Bar.Items IsNot Nothing Then
...
Il codice sta testando solo Items
entrambi myFoo
e Bar
potrebbe anche essere Nothing. Il rimedio è testare l'intera catena o percorso di oggetti uno alla volta:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
è importante. I test successivi non verranno eseguiti una volta False
riscontrata la prima condizione. Ciò consente al codice di "eseguire il drill" in modo sicuro nell'oggetto (i) un "livello" alla volta, valutando myFoo.Bar
solo dopo (e se) che myFoo
è stato ritenuto valido. Le catene di oggetti o i percorsi possono diventare piuttosto lunghi quando si codificano oggetti complessi:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
Non è possibile fare riferimento a nulla "a valle" di un null
oggetto. Questo vale anche per i controlli:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Qui, myWebBrowser
o Document
potrebbe essere Nothing o l' formfld1
elemento potrebbe non esistere.
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)
Tra le altre cose, questo codice non prevede che l'utente potrebbe non aver selezionato qualcosa in uno o più controlli dell'interfaccia utente. ListBox1.SelectedItem
potrebbe anche essere Nothing
, quindi ListBox1.SelectedItem.ToString
si tradurrà in un NRE.
Rimedio
Convalida i dati prima di utilizzarli (usa anche Option Strict
i parametri 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
In alternativa, puoi usare (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
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
Questo è un modo abbastanza comune per ottenere un NRE. In C #, a seconda di come è codificato, l'IDE riporterà che Controls
non esiste nel contesto corrente o "non può fare riferimento a un membro non statico". Quindi, in una certa misura, questa è solo una situazione di VB. È anche complesso perché può causare una cascata di guasti.
Le matrici e le raccolte non possono essere inizializzate in questo modo. Questo codice di inizializzazione verrà eseguito prima che il costruttore crei il Form
o il Controls
. Di conseguenza:
somevar
assegnazione si tradurrà in un NRE immediato perché Nothing non ha una .Text
proprietàIl riferimento successivo agli elementi dell'array genererà un NRE. Se lo fai in Form_Load
, a causa di un bug strano, l'IDE potrebbe non segnalare l'eccezione quando si verifica. L'eccezione verrà visualizzata in seguito quando il codice tenta di utilizzare l'array. Questa "eccezione silenziosa" è dettagliata in questo post . Per i nostri scopi, la chiave è che quando si verifica qualcosa di catastrofico durante la creazione di un modulo ( Sub New
o Form Load
evento), le eccezioni potrebbero non essere segnalate, il codice esce dalla procedura e visualizza semplicemente il modulo.
Poiché nessun altro codice nel tuo Sub New
o Form Load
evento verrà eseguito dopo NRE, molte altre cose possono essere lasciate non inizializzate.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Nota che questo vale per tutti i controlli e tutti i riferimenti ai componenti che li rendono illegali dove sono:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Rimedio parziale
E 'curioso che VB non fornisce un avvertimento, ma il rimedio è quello di dichiarare i contenitori a livello di modulo, ma inizializzare loro in gestione dell'evento load forma quando i controlli fanno esistere. Questo può essere fatto Sub New
fintanto che il codice è dopo la InitializeComponent
chiamata:
' 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
Il codice dell'array potrebbe non essere ancora fuori dal comune. Qualsiasi controllo che si trova in un controllo contenitore (come un GroupBox
o Panel
) non verrà trovato in Me.Controls
; saranno nella raccolta Controlli di quel Pannello o GroupBox. Né verrà restituito un controllo quando il nome del controllo è errato ( "TeStBox2"
). In tali casi, Nothing
verrà nuovamente memorizzato in quegli elementi dell'array e si verificherà un NRE quando si tenta di fare riferimento a esso.
Questi dovrebbero essere facili da trovare ora che sai cosa stai cercando:
"Button2" risiede su a Panel
Rimedio
Invece di riferimenti indiretti per nome utilizzando la Controls
raccolta del modulo , utilizzare il riferimento di controllo:
' 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
Questo è un caso in cui l'IDE ti avvertirà che " non tutti i percorsi restituiscono un valore e un NullReferenceException
risultato può essere ". È possibile eliminare l'avviso sostituendolo Exit Function
con Return Nothing
, ma ciò non risolve il problema. Tutto ciò che tenta di utilizzare il ritorno quando someCondition = False
si tradurrà in un NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Rimedio
Sostituire Exit Function
nella funzione con Return bList
. Restituire un vuoto List
non equivale a restituire Nothing
. Se esiste la possibilità che un oggetto restituito possa essere Nothing
, provare prima di usarlo:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Un Try / Catch mal implementato può nascondere dove si trova il problema e provocarne di nuovi:
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
Questo è un caso in cui un oggetto non viene creato come previsto, ma dimostra anche la controutilità di un vuoto Catch
.
C'è una virgola aggiuntiva nell'SQL (dopo 'mailaddress') che si traduce in un'eccezione in .ExecuteReader
. Dopo Catch
che non fa nulla, Finally
tenta di eseguire la pulizia, ma poiché non è possibile Close
un DataReader
oggetto null , si NullReferenceException
ottengono risultati nuovi di zecca .
Un Catch
blocco vuoto è il parco giochi del diavolo. Questo OP era sconcertato dal motivo per cui stava ottenendo un NRE nel Finally
blocco. In altre situazioni, un vuoto Catch
può causare qualcos'altro molto più a valle che va in tilt e farti passare il tempo a guardare le cose sbagliate nel posto sbagliato per il problema. (La "eccezione silenziosa" sopra descritta fornisce lo stesso valore di intrattenimento.)
Rimedio
Non utilizzare blocchi Try / Catch vuoti: lasciare che il codice si blocchi in modo da poter a) identificare la causa b) identificare la posizione ec) applicare un rimedio adeguato. I blocchi Try / Catch non hanno lo scopo di nascondere le eccezioni alla persona qualificata in modo univoco per risolverli: lo sviluppatore.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
La IsDBNull
funzione viene utilizzata per verificare se un valore è uguale a System.DBNull
: Da MSDN:
Il valore System.DBNull indica che l'Oggetto rappresenta dati mancanti o inesistenti. DBNull non è uguale a Nothing, il che indica che una variabile non è stata ancora inizializzata.
Rimedio
If row.Cells(0) IsNot Nothing Then ...
Come prima, puoi provare per Nothing, quindi per un valore specifico:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Esempio 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
restituisce il primo elemento o il valore predefinito, che è Nothing
per i tipi di riferimento e mai DBNull
:
If getFoo IsNot Nothing Then...
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
Se un CheckBox
con chkName
non può essere trovato (o esiste in a GroupBox
), allora chk
sarà Nothing e il tentativo di fare riferimento a qualsiasi proprietà comporterà un'eccezione.
Rimedio
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
Il DGV presenta alcune stranezze periodicamente:
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"
Se dgvBooks
ha AutoGenerateColumns = True
, creerà le colonne, ma non li nome, in modo che il codice di cui sopra non riesce quando li fa riferimento al nome.
Rimedio
Denominare le colonne manualmente o fare riferimento per indice:
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
Quando il tuo DataGridView
è AllowUserToAddRows
come True
(impostazione predefinita), Cells
conterrà la riga vuota / nuova in fondo Nothing
. La maggior parte dei tentativi di utilizzare i contenuti (ad esempio ToString
) comporterà un NRE.
Rimedio
Utilizzare un For/Each
ciclo e testare la IsNewRow
proprietà per determinare se si tratta dell'ultima riga. Questo funziona se AllowUserToAddRows
è vero o no:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
Se si utilizza un For n
ciclo, modificare il conteggio delle righe o utilizzare Exit For
quando IsNewRow
è vero.
In determinate circostanze, il tentativo di utilizzare un elemento da My.Settings
cui è StringCollection
possibile può comportare un riferimento null la prima volta che lo si utilizza. La soluzione è la stessa, ma non così ovvia. Prendere in considerazione:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Poiché VB gestisce le impostazioni per te, è ragionevole aspettarsi che inizializzi la raccolta. Lo farà, ma solo se in precedenza hai aggiunto una voce iniziale alla raccolta (nell'editor delle impostazioni). Poiché la raccolta viene (apparentemente) inizializzata quando viene aggiunto un elemento, rimane Nothing
quando non ci sono elementi nell'editor Impostazioni da aggiungere.
Rimedio
Inizializza la raccolta delle impostazioni nel Load
gestore eventi del modulo , se / quando necessario:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
In genere, la Settings
raccolta dovrà essere inizializzata solo al primo avvio dell'applicazione. Un rimedio alternativo è aggiungere un valore iniziale alla tua raccolta in Progetto -> Impostazioni | FooBars , salva il progetto, quindi rimuovi il valore falso.
Probabilmente hai dimenticato l' New
operatore.
o
Qualcosa che hai assunto avrebbe funzionato in modo impeccabile per restituire un oggetto inizializzato al tuo codice, non lo ha fatto.
Non ignorare gli avvisi del compilatore (mai) e utilizzare Option Strict On
(sempre).
Un altro scenario è quando si lancia un oggetto null in un tipo di valore . Ad esempio, il codice seguente:
object o = null;
DateTime d = (DateTime)o;
Lancerà a NullReferenceException
sul cast. Sembra abbastanza ovvio nell'esempio precedente, ma ciò può accadere in scenari complessi più "late-binding" in cui l'oggetto null è stato restituito da un codice che non si possiede e il cast è ad esempio generato da un sistema automatico.
Un esempio di questo è questo semplice frammento di associazione ASP.NET con il controllo Calendar:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Qui, SelectedDate
in effetti , è una proprietà - di DateTime
tipo - del Calendar
tipo di controllo Web e l'associazione potrebbe restituire perfettamente qualcosa di nullo. Il generatore ASP.NET implicito creerà un pezzo di codice che sarà equivalente al codice cast sopra. E questo genererà un problema NullReferenceException
che è abbastanza difficile da individuare, perché risiede nel codice generato da ASP.NET che compila bene ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Significa che la variabile in questione non punta a nulla. Potrei generarlo così:
SqlConnection connection = null;
connection.Open();
Ciò genererà l'errore perché mentre ho dichiarato la variabile " connection
", non ha puntato a nulla. Quando provo a chiamare il membro " Open
", non c'è alcun riferimento per la sua risoluzione e genererà l'errore.
Per evitare questo errore:
object == null
.Lo strumento Resharper di JetBrains identificherà ogni posizione nel codice che ha la possibilità di un errore di riferimento null, consentendoti di effettuare un controllo null. Questo errore è la fonte numero uno di bug, IMHO.
Significa che il tuo codice ha utilizzato una variabile di riferimento all'oggetto impostata su null (ovvero non ha fatto riferimento a un'istanza effettiva dell'oggetto).
Per evitare l'errore, gli oggetti che potrebbero essere nulli devono essere testati per null prima di essere utilizzati.
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
}
Tieni presente che, indipendentemente dallo scenario, la causa è sempre la stessa in .NET:
Stai tentando di utilizzare una variabile di riferimento il cui valore è
Nothing
/null
. Quando il valore èNothing
/null
per la variabile di riferimento, significa che in realtà non contiene un riferimento a un'istanza di alcun oggetto esistente nell'heap.Non hai mai assegnato qualcosa alla variabile, non hai mai creato un'istanza del valore assegnato alla variabile o hai impostato la variabile uguale a
Nothing
/null
manualmente o hai chiamato una funzione che imposta la variabile suNothing
/null
per te.
Un esempio di questa eccezione generata è: quando si tenta di controllare qualcosa, questo è nullo.
Per esempio:
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
}
Il runtime .NET genererà una NullReferenceException quando si tenta di eseguire un'azione su qualcosa che non è stato istanziato, ad esempio il codice sopra.
In confronto a una ArgumentNullException che viene generalmente lanciata come misura difensiva se un metodo prevede che ciò che gli viene passato non sia nullo.
Ulteriori informazioni sono disponibili in N # NullReferenceException e Null Parameter .
Aggiornamento C # 8.0, 2019: tipi di riferimento nullable
C # 8.0 introduce tipi di riferimento annullabili e tipi di riferimento non annullabili . Pertanto, per evitare una NullReferenceException, è necessario verificare solo i tipi di riferimento nullable .
Se non è stato inizializzato un tipo di riferimento e si desidera impostare o leggere una delle sue proprietà, verrà generata un'eccezione NullReferenceException .
Esempio:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Puoi semplicemente evitarlo controllando se la variabile non è nulla:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Per comprendere appieno il motivo per cui viene generata una NullReferenceException, è importante conoscere la differenza tra tipi di valore e [tipi di riferimento] [3].
Quindi, se hai a che fare con tipi di valore , non possono verificarsi NullReferenceExceptions . Tuttavia, devi stare attento quando hai a che fare con i tipi di riferimento !
Solo i tipi di riferimento, come suggerisce il nome, possono contenere riferimenti o puntare letteralmente a nulla (o "null"). Considerando che i tipi di valore contengono sempre un valore.
Tipi di riferimento (questi devono essere controllati):
Tipi di valore (puoi semplicemente ignorare questi):
Un altro caso in cui NullReferenceExceptions
può accadere è l'uso (errato) as
dell'operatore :
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
Qui, Book
e Car
sono tipi incompatibili; a Car
non può essere convertito / cast in a Book
. Quando questo cast fallisce, as
ritorna null
. L'uso mybook
dopo ciò causa aNullReferenceException
.
In generale, dovresti usare un cast o as
, come segue:
Se ti aspetti che la conversione del tipo abbia sempre successo (ad es. Sai quale oggetto dovrebbe essere in anticipo), allora dovresti usare un cast:
ComicBook cb = (ComicBook)specificBook;
Se non si è sicuri del tipo, ma si desidera provare a utilizzarlo come tipo specifico, utilizzare as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Si sta utilizzando l'oggetto che contiene il riferimento di valore null. Quindi sta dando un'eccezione nulla. Nell'esempio il valore della stringa è nullo e durante il controllo della sua lunghezza si è verificata l'eccezione.
Esempio:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
L'errore di eccezione è:
Eccezione non gestita:
System.NullReferenceException: riferimento all'oggetto non impostato su un'istanza di un oggetto. at Program.Main ()
Mentre ciò che causa un NullReferenceExceptions e gli approcci per evitare / correggere tale eccezione sono stati affrontati in altre risposte, ciò che molti programmatori non hanno ancora imparato è come eseguire il debug in modo indipendente di tali eccezioni durante lo sviluppo.
In Visual Studio questo è generalmente facile grazie al debugger di Visual Studio .
Innanzitutto, assicurati che l'errore corretto venga rilevato - vedi Come posso consentire l'interruzione di "System.NullReferenceException" in VS2010? Nota 1
Quindi iniziare con il debug (F5) o collegare [il debugger VS] al processo in esecuzione . A volte può essere utile da usareDebugger.Break
, che richiederà di avviare il debugger.
Ora, quando viene generata (o non gestita) NullReferenceException, il debugger si interromperà (ricordi la regola impostata sopra?) Sulla riga in cui si è verificata l'eccezione. A volte l'errore sarà facile da individuare.
Ad esempio, nella riga seguente l'unico codice che può causare l'eccezione è se viene myString
valutato su null. Questo può essere verificato guardando la Finestra di controllo o eseguendo espressioni nella Finestra immediata .
var x = myString.Trim();
In casi più avanzati, come i seguenti, è necessario utilizzare una delle tecniche sopra (Guarda o Windows immediato) per ispezionare le espressioni per determinare se str1
era nullo o se str2
era nullo.
var x = str1.Trim() + str2.Trim();
Una volta in cui l'eccezione è a due è stato localizzato, di solito banale ragione a ritroso per scoprire dove il valore null è stato [errato] ha introdotto -
Prenditi il tempo necessario per capire la causa dell'eccezione. Controlla le espressioni null. Ispeziona le espressioni precedenti che potrebbero aver provocato espressioni nulle. Aggiungi punti di interruzione ed esegui il programma come appropriato. Usa il debugger.
1 Se Break on Throws è troppo aggressivo e il debugger si arresta su un NPE nella libreria .NET o di terze parti, Break on User-Unhandled può essere utilizzato per limitare le eccezioni rilevate. Inoltre, VS2012 introduce Just My Code che consiglio anche di abilitare.
Se si esegue il debug con Just My Code abilitato, il comportamento è leggermente diverso. Con Just My Code abilitato, il debugger ignora le eccezioni di Common Language Runtime (CLR) di prima possibilità che vengono generate all'esterno di My Code e non passano attraverso My Code
Simon Mourier ha dato questo esempio :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
dove una conversione unboxing (cast) da object
(o da una delle classi System.ValueType
o System.Enum
, o da un tipo di interfaccia) a un tipo di valore (diverso da Nullable<>
) in sé fornisceNullReferenceException
.
Nell'altra direzione, una conversione di boxe da un Nullable<>
che è HasValue
uguale false
a un tipo di riferimento, può dare un null
riferimento che può poi portare a NullReferenceException
. L'esempio classico è:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
A volte la boxe avviene in un altro modo. Ad esempio con questo metodo di estensione non generico:
public static void MyExtension(this object x)
{
x.ToString();
}
il seguente codice sarà problematico:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Questi casi sorgono a causa delle regole speciali utilizzate dal runtime durante le Nullable<>
istanze di inscatolamento .
Aggiunta di un caso in cui il nome della classe per l'entità utilizzata nel framework dell'entità è uguale al nome della classe per un file code-behind del modulo Web.
Supponiamo di avere un modulo Web Contact.aspx la cui codebehind classe è Contact e di avere un nome di entità Contact.
Quindi il codice seguente genererà una NullReferenceException quando si chiama context.SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Per completezza della classe DataContext
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
e contattare la classe di entità. A volte le classi di entità sono classi parziali in modo da poterle estendere anche in altri file.
public partial class Contact
{
public string Name {get; set;}
}
L'errore si verifica quando sia l'entità che la classe codebehind si trovano nello stesso spazio dei nomi. Per risolvere questo problema, rinominare la classe entità o la classe codebehind per Contact.aspx.
Motivo Non sono ancora sicuro del motivo. Ma ogni qualvolta una delle entità della classe estenderà System.Web.UI.Page questo errore si verifica.
Per la discussione dai un'occhiata a NullReferenceException in DbContext.saveChanges ()
Un altro caso generale in cui si potrebbe ricevere questa eccezione riguarda le classi beffardo durante i test delle unità. Indipendentemente dal framework di derisione utilizzato, è necessario assicurarsi che tutti i livelli appropriati della gerarchia di classi siano correttamente derisi. In particolare, tutte le proprietà a HttpContext
cui fa riferimento il codice in prova devono essere derise.
Vedere " NullReferenceException generata durante il test di AuthorizationAttribute personalizzato " per un esempio un po 'dettagliato.
Ho una prospettiva diversa per rispondere a questo. Questo tipo di risposte "cos'altro posso fare per evitarlo? "
Quando si lavora su diversi livelli , ad esempio in un'applicazione MVC, un controller ha bisogno di servizi per chiamare le operazioni aziendali. In tali scenari, è possibile utilizzare il contenitore di iniezione di dipendenza per inizializzare i servizi per evitare NullReferenceException . Ciò significa che non è necessario preoccuparsi di verificare la presenza di null e chiamare semplicemente i servizi dal controller come se fossero sempre disponibili (e inizializzati) come singleton o prototipo.
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();
}
}
Sulla questione di "cosa dovrei fare al riguardo" , ci possono essere molte risposte.
Un modo più "formale" di prevenire tali condizioni di errore durante lo sviluppo è applicare il design per contratto nel codice. Ciò significa che è necessario impostare invarianti di classe e / o persino precondizioni di funzione / metodo e postcondizioni sul proprio sistema durante lo sviluppo.
In breve, invarianti di classe assicurano che ci saranno alcuni vincoli nella tua classe che non verranno violati nell'uso normale (e quindi la classe non entrerà in uno stato incoerente). Presupposti indicano che i dati forniti come input per una funzione / metodo devono seguire alcuni set di vincoli e non violarli mai , e postcondizioni significano che un output di funzione / metodo deve seguire nuovamente i vincoli impostati senza mai violarli. Le condizioni del contratto non devono mai essere violate durante l'esecuzione di un programma privo di bug, pertanto la progettazione per contratto è verificata in pratica in modalità debug, mentre è disabilitata nelle versioni , per massimizzare le prestazioni del sistema sviluppato.
In questo modo, è possibile evitare NullReferenceException
casi che sono il risultato della violazione dei vincoli impostati. Ad esempio, se si utilizza una proprietà oggetto X
in una classe e successivamente si tenta di invocare uno dei suoi metodi e X
ha un valore nullo, ciò comporterà NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Ma se si imposta "la proprietà X non deve mai avere un valore nullo" come condizione preliminare del metodo, è possibile impedire lo scenario descritto in precedenza:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Per questa causa, esiste un progetto di Contratti di codice per le applicazioni .NET.
In alternativa, la progettazione per contratto può essere applicata mediante asserzioni .
AGGIORNARE: Vale la pena ricordare che il termine è stato coniato da Bertrand Meyer in relazione al suo design del linguaggio di programmazione Eiffel .
A NullReferenceException
viene generato quando si tenta di accedere alle proprietà di un oggetto null o quando un valore di stringa diventa vuoto e si tenta di accedere ai metodi di stringa.
Per esempio:
Quando si accede a un metodo stringa di una stringa vuota:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Quando si accede a una proprietà di un oggetto null:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
non genererà un'eccezione di riferimento null. Rappresenta una stringa effettiva, sebbene vuota (es ""
.). Dato che questo ha un oggetto da chiamare ToLower()
, non avrebbe senso lanciare un'eccezione di riferimento null lì.
TL; DR: prova a utilizzare Html.Partial
invece diRenderpage
Stavo ottenendo Object reference not set to an instance of an object
quando ho provato a eseguire il rendering di una vista in una vista inviandola un modello, in questo modo:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Il debug ha mostrato che il modello era Null in MyOtherView. Fino a quando non l'ho cambiato in:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
E ha funzionato.
Inoltre, il motivo per cui non dovevo Html.Partial
cominciare era perché a volte Visual Studio lanciava linee ondulate che sembravano errori Html.Partial
se si trova all'interno di un foreach
ciclo costruito diversamente , anche se non è davvero un errore:
@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>
Ma sono stato in grado di eseguire l'applicazione senza problemi con questo "errore". Sono stato in grado di sbarazzarmi dell'errore modificando la struttura del foreach
loop in questo modo:
@foreach(var M in MyEntities){
...
}
Anche se ho la sensazione che sia stato perché Visual Studio ha letto male le e commerciali e le parentesi.
Html.Partial
, non@Html.Partial
Null
), quindi sapevo che l'errore riguardava il modo in cui lo stavo inviando.
Cosa puoi fare al riguardo?
Ci sono molte buone risposte qui che spiegano cos'è un riferimento null e come eseguirne il debug. Ma c'è molto poco su come prevenire il problema o almeno renderlo più facile da rilevare.
Controlla gli argomenti
Ad esempio, i metodi possono controllare i diversi argomenti per vedere se sono nulli e generare un ArgumentNullException
, un'eccezione ovviamente creata per questo preciso scopo.
Il costruttore per il ArgumentNullException
pari prende il nome del parametro e un messaggio come argomenti in modo da poter dire esattamente allo sviluppatore qual è il problema.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Usa gli strumenti
Ci sono anche diverse librerie che possono aiutare. "Resharper", ad esempio, può fornire avvisi durante la scrittura del codice, soprattutto se si utilizza il loro attributo: NotNullAttribute
Esistono "Contratti di codice Microsoft" in cui si utilizza la sintassi, ad esempio, Contract.Requires(obj != null)
che consente di verificare il tempo di esecuzione e la compilazione: Presentazione dei contratti di codice .
C'è anche "PostSharp" che ti permetterà di usare solo attributi come questo:
public void DoSometing([NotNull] obj)
In questo modo e rendendo PostSharp parte del processo di compilazione obj
verrà verificato null durante l'esecuzione. Vedi: PostSharp null check
Soluzione di codice semplice
Oppure puoi sempre codificare il tuo approccio usando un semplice vecchio codice. Ad esempio, ecco una struttura che puoi usare per catturare riferimenti null. È modellato sullo stesso concetto di Nullable<T>
:
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
Useresti molto simile allo stesso modo in cui useresti Nullable<T>
, tranne con l'obiettivo di ottenere esattamente il contrario - per non permettere null
. Ecco alcuni esempi:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
viene implicitamente trasmesso da e verso in T
modo da poterlo utilizzare praticamente ovunque tu ne abbia bisogno. Ad esempio, è possibile passare un Person
oggetto a un metodo che accetta un NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Come puoi vedere sopra come con nullable, accedi al valore sottostante tramite la Value
proprietà. In alternativa, puoi utilizzare un cast esplicito o implicito, puoi vedere un esempio con il valore restituito di seguito:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Oppure puoi anche usarlo quando il metodo ritorna T
(in questo caso Person
) semplicemente eseguendo un cast. Ad esempio, il seguente codice vorrebbe solo il codice sopra:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combina con l'estensione
Combina NotNull<T>
con un metodo di estensione e puoi coprire ancora più situazioni. Ecco un esempio di come può apparire il metodo di estensione:
[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;
}
}
Ed ecco un esempio di come potrebbe essere usato:
var person = GetPerson().NotNull();
GitHub
Per tuo riferimento ho reso disponibile il codice sopra su GitHub, puoi trovarlo su:
https://github.com/luisperezphd/NotNull
Funzionalità della lingua correlata
C # 6.0 ha introdotto l '"operatore null condizionale" che aiuta un po' in questo. Con questa funzione, puoi fare riferimento a oggetti nidificati e se uno di essi è null
l'intera espressione restituita null
.
Ciò riduce il numero di controlli null da eseguire in alcuni casi. La sintassi consiste nel mettere un punto interrogativo prima di ogni punto. Prendi ad esempio il seguente codice:
var address = country?.State?.County?.City;
Immagina che country
sia un oggetto di tipo Country
che ha una proprietà chiamata State
e così via. Se country
, State
, County
, o City
è null
quindi address will be
nullo . Therefore you only have to check whether
indirizzo is
null`.
È una grande funzionalità, ma ti dà meno informazioni. Non è ovvio quale dei 4 sia nullo.
Incorporato come Nullable?
C # ha una bella scorciatoia per Nullable<T>
, puoi rendere nulla nullable inserendo un punto interrogativo dopo il tipo in questo modo int?
.
Sarebbe bello se C # avuto qualcosa di simile alla NotNull<T>
struct sopra e aveva una stenografia simile, forse il punto esclamativo in modo che si potrebbe scrivere qualcosa di simile (!): public void WriteName(Person! person)
.
È interessante notare che nessuna delle risposte in questa pagina menziona i due casi limite, spero che nessuno se ne occupi se li aggiungo:
I dizionari generici in .NET non sono thread-safe e a volte potrebbero lanciare NullReference
o addirittura (più frequente) aKeyNotFoundException
quando si tenta di accedere a una chiave da due thread simultanei. L'eccezione è abbastanza fuorviante in questo caso.
Se a NullReferenceException
viene generato un unsafe
codice, è possibile esaminare le variabili del puntatore e verificarleIntPtr.Zero
o altro. Che è la stessa cosa ("eccezione puntatore nullo"), ma in un codice non sicuro, le variabili vengono spesso espresse in tipi di valore / array, ecc. E si sbatte la testa contro il muro, chiedendosi come un tipo di valore può lanciare questo eccezione.
(Un altro motivo per non usare codice non sicuro a meno che tu non ne abbia bisogno, comunque)
null
in che modo?
È possibile correggere NullReferenceException in modo pulito utilizzando gli operatori Null-conditional in c # 6 e scrivere meno codice per gestire i controlli null.
Viene utilizzato per verificare la presenza di null prima di eseguire un'operazione di accesso (?.) O indice (? [) Del membro.
Esempio
var name = p?.Spouse?.FirstName;
è equivalente a:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
Il risultato è che il nome sarà null quando p è null o quando p.Spouse è null.
In caso contrario, al nome della variabile verrà assegnato il valore di p.Spouse.FirstName.
Per maggiori dettagli: Operatori nulli
La riga di errore "Riferimento oggetto non impostato su un'istanza di un oggetto" indica che non è stato assegnato un oggetto istanza a un riferimento oggetto e si sta ancora accedendo a proprietà / metodi di quell'oggetto.
per esempio: supponiamo che tu abbia una classe chiamata myClass e contenga una proprietà prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Ora stai accedendo a questo prop1 in qualche altra classe proprio come sotto:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
la riga sopra genera errore perché il riferimento della classe myClass è dichiarato ma non istanziato o un'istanza di oggetto non è assegnata al riferimento di quella classe.
Per risolvere questo problema è necessario creare un'istanza (assegnare l'oggetto al riferimento di quella classe).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
Il riferimento NullReferenceException o Object non impostato su un'istanza di un oggetto si verifica quando un oggetto della classe che si sta tentando di utilizzare non viene istanziato. Per esempio:
Supponi di avere una classe chiamata Student.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Ora, considera un'altra lezione in cui stai cercando di recuperare il nome completo dello studente.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Come visto nel codice sopra, la dichiarazione Student s - dichiara solo la variabile di tipo Student, nota che la classe Student non è istanziata a questo punto. Quindi, quando viene eseguita l'istruzione s.GetFullName () , genererà NullReferenceException.
Bene, in termini semplici:
Stai tentando di accedere a un oggetto che non è stato creato o che al momento non è in memoria.
Quindi, come affrontare questo:
Effettua il debug e lascia che il debugger si rompa ... Ti porterà direttamente alla variabile che è rotta ... Ora il tuo compito è semplicemente quello di risolvere questo problema .. Usando la nuova parola chiave nel posto appropriato.
Se è causato da alcuni comandi del database perché l'oggetto non è presente, è sufficiente fare un controllo nullo e gestirlo:
if (i == null) {
// Handle this
}
Il più difficile .. se il GC ha già raccolto l'oggetto ... Ciò si verifica in genere se si sta cercando di trovare un oggetto usando le stringhe ... Cioè, trovandolo per nome dell'oggetto, può accadere che il GC potrebbe già ripulito ... Questo è difficile da trovare e diventerà un problema ... Un modo migliore per affrontarlo è fare controlli nulli ove necessario durante il processo di sviluppo. Questo ti farà risparmiare un sacco di tempo.
Trovando per nome intendo un po 'di framework che consente a FIndObjects di usare stringhe e il codice potrebbe apparire così: FindObject ("ObjectName");
Letteralmente il modo più semplice per riparare un NullReferenceExeption ha due modi. Se hai un GameObject, ad esempio, con uno script allegato e una variabile denominata rb (rigidbody), questa variabile inizierà null quando inizi il gioco.
Questo è il motivo per cui si ottiene NullReferenceExeption perché il computer non ha dati memorizzati in quella variabile.
Userò una variabile RigidBody come esempio.
Possiamo aggiungere dati davvero facilmente in realtà in alcuni modi:
rb = GetComponent<Rigidbody>();
Start()
o Awake()
funzioni. rb = AddComponent<RigidBody>();
Ulteriori note: se vuoi che l'unità aggiunga un componente al tuo oggetto e potresti aver dimenticato di aggiungerne uno, puoi digitare [RequireComponent(typeof(RigidBody))]
sopra la tua dichiarazione di classe (lo spazio sotto tutti i tuoi utilizzi).
Divertiti e divertiti a creare giochi!
Se consideriamo scenari comuni in cui è possibile generare questa eccezione, accedendo alle proprietà con l'oggetto in alto.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
qui, se l'indirizzo è null, otterrai NullReferenceException.
Quindi, come pratica, dovremmo sempre usare il controllo null, prima di accedere alle proprietà di tali oggetti (specialmente in termini generici)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Questa è fondamentalmente un'eccezione di riferimento Null . Come afferma Microsoft-
Viene generata un'eccezione NullReferenceException quando si tenta di accedere a un membro di un tipo il cui valore è null.
Ciò significa che se un membro che non detiene alcun valore e lo stiamo facendo per eseguire determinate attività, il sistema lancerà senza dubbio un messaggio e dirà:
"Ehi aspetta, quel membro non ha valori, quindi non può eseguire l'attività che lo stai consegnando."
L'eccezione stessa afferma che viene fatto riferimento a qualcosa ma il cui valore non viene impostato. Quindi questo indica che si verifica solo durante l'utilizzo di tipi di riferimento poiché i tipi di valore non sono annullabili.
NullReferenceException non si verificherà se utilizziamo membri del tipo Value.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
Il codice sopra mostra una stringa semplice che è assegnata con un null valore .
Ora, quando provo a stampare la lunghezza della stringa str , ottengo un'eccezione non gestita del tipo "System.NullReferenceException" che si è verificato perché il membro str punta a null e non può esserci alcuna lunghezza di null.
' NullReferenceException ' si verifica anche quando dimentichiamo di creare un'istanza di un tipo di riferimento.
Supponiamo di avere una classe e un metodo membro. Non ho istanziato la mia classe, ma ho solo chiamato la mia classe. Ora, se provo ad usare il metodo, il compilatore genererà un errore o emetterà un avviso (a seconda del compilatore).
class Program
{
static void Main(string[] args)
{
MyClass1 obj;
obj.foo(); //Use of unassigned local variable 'obj'
}
}
public class MyClass1
{
internal void foo()
{
Console.WriteLine("hello from foo");
}
}
Il compilatore per il codice sopra riportato genera un errore che la variabile obj non è assegnata, il che significa che la nostra variabile ha valori nulli o nulla. Il compilatore per il codice sopra riportato genera un errore che la variabile obj non è assegnata, il che significa che la nostra variabile ha valori nulli o nulla.
NullReferenceException nasce a causa di un nostro errore per non aver verificato il valore dell'oggetto. Spesso lasciamo deselezionati i valori degli oggetti nello sviluppo del codice.
Sorge anche quando ci dimentichiamo di istanziare i nostri oggetti. L'uso di metodi, proprietà, raccolte ecc. Che possono restituire o impostare valori null può anche essere la causa di questa eccezione.
Esistono vari modi e metodi per evitare questa rinomata eccezione:
Controllo esplicito: dovremmo aderire alla tradizione del controllo di oggetti, proprietà, metodi, matrici e raccolte se sono nulli. Questo può essere semplicemente implementato usando istruzioni condizionali come if-else if-else ecc.
Gestione delle eccezioni: uno dei modi importanti per gestire questa eccezione. Utilizzando semplici blocchi try-catch-finally possiamo controllare questa eccezione e conservarne anche un registro. Questo può essere molto utile quando l'applicazione è in fase di produzione.
Operatori null: l'operatore Null Coalescing e gli operatori null null possono anche essere utili quando si impostano valori su oggetti, variabili, proprietà e campi.
Debugger: per gli sviluppatori, abbiamo la grande arma del debugging con noi. Se abbiamo affrontato NullReferenceException durante la faccia di sviluppo, possiamo usare il debugger per arrivare alla fonte dell'eccezione.
Metodo integrato: metodi di sistema come GetValueOrDefault (), IsNullOrWhiteSpace () e IsNullorEmpty () verifica la presenza di valori null e assegna il valore predefinito se esiste un valore null.
Ci sono già molte buone risposte qui. Puoi anche controllare una descrizione più dettagliata con esempi sul mio blog .
Spero che questo aiuti anche!
Se uno riceve questo messaggio durante il salvataggio o la compilazione della build, basta chiudere tutti i file e quindi aprire qualsiasi file per compilare e salvare.
Per me il motivo era che avevo rinominato il file e il vecchio file era ancora aperto.