c# >: object - Cos'è una NullReferenceException e come risolverlo?





15 Answers

Eccezione NullReference - Visual Basic

L' NullReference Exception per Visual Basic non è diversa da quella in C # . Dopo tutto, entrambi riportano la stessa eccezione definita in .NET Framework che entrambi utilizzano. 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 domande passate di Stack Overflow. Questo per massimizzare la pertinenza utilizzando i tipi di situazioni che si vedono spesso nei post. Un po 'più di spiegazione è prevista anche per coloro che potrebbero averne bisogno. Un esempio simile al tuo è molto probabilmente elencato qui.

Nota:

  1. Questo è basato su concetti: non c'è un codice da incollare nel tuo progetto. Ha lo scopo di aiutarti a capire cosa causa una NullReferenceException (NRE), come trovarla, come risolverla e come evitarla. Un NRE può essere causato in molti modi, quindi è improbabile che sia il tuo unico incontro.
  2. Gli esempi (dai post Stack Overflow) non sempre mostrano il modo migliore per fare qualcosa in primo luogo.
  3. In genere, viene utilizzato il rimedio più semplice.

Significato di base

Il messaggio "Oggetto non impostato su un'istanza di oggetto" indica che stai tentando di utilizzare un oggetto che non è stato inizializzato. Questo si riduce a uno di questi:

  • Il tuo codice ha dichiarato una variabile oggetto, ma non l'ha inizializzata (crea un'istanza o " crea un'istanza ")
  • Qualcosa che il tuo codice supponeva avrebbe inizializzato un oggetto, no
  • Forse, un altro codice ha invalidato prematuramente un oggetto ancora in uso

Trovare la causa

Poiché il problema è un riferimento a un oggetto che è Nothing , la risposta è esaminarli per scoprire quale. Quindi determinare il motivo per cui non è inizializzato. Tieni il mouse sulle varie variabili e Visual Studio (VS) mostrerà i loro valori - il colpevole sarà Nothing .

Dovresti anche rimuovere tutti i blocchi Try / Catch dal codice rilevante, specialmente quelli in cui non c'è nulla nel blocco Catch. Ciò causerà il blocco del codice quando tenta di utilizzare un oggetto che è Nothing . Questo è ciò che vuoi perché identifica la posizione esatta del problema e ti consente di identificare l'oggetto che lo causa.

Un MsgBox nel Catch che visualizza Error while... sarà di scarso aiuto. Questo metodo porta anche a pessime domande di overflow dello stack, perché non è possibile descrivere l'eccezione effettiva, l'oggetto coinvolto o persino la riga di codice in cui si verifica.

Puoi anche usare la Locals Window ( Debug -> Windows -> Locali ) per esaminare i tuoi oggetti.

Una volta che sai cosa e dove è il problema, di solito è abbastanza facile da correggere e più veloce di pubblicare una nuova domanda.

Guarda anche:

Esempi e rimedi

Oggetti di classe / Creazione di un'istanza

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'operatore New può spesso essere utilizzato per creare l'istanza quando la si dichiara:

Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor

' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister

Quando è solo opportuno creare l'istanza in un secondo momento:

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

Nota: non utilizzare nuovamente Dim in una procedura, incluso il costruttore ( Sub New ):

Private reg As CashRegister
'...

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

Questo creerà una variabile locale , reg , che esiste solo in quel contesto (sotto). La variabile reg con Scope level level che userete ovunque rimane Nothing .

Manca l'operatore New è la causa n. 1 delle NullReference Exceptions viste nelle domande di Overflow dello stack esaminate.

Visual Basic tenta di rendere chiaro il processo ripetutamente utilizzando New : Using the New Operator crea un nuovo oggetto e chiama Sub New - the constructor - dove l'oggetto può eseguire qualsiasi altra inizializzazione.

Per essere chiari, Dim (o Private ) dichiara solo una variabile e il suo Type . L' ambito della variabile, indipendentemente dal fatto che esista per l'intero modulo / classe o sia locale per una procedura, è determinato dalla posizione in cui è dichiarato. Private | Friend | Public Private | Friend | Public definisce il livello di accesso, non Ambito .

Per ulteriori informazioni, vedere:

Array

Le matrici devono anche essere istanziate:

Private arr as String()

Questo array è stato 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 utilizzando 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 che vengono assegnati. Le dichiarazioni di 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 oggetti Foo in esso non ce l'hanno.

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 una List(Of T) renderà piuttosto 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:

Elenchi e collezioni

Le raccolte .NET (di cui ci sono molte varietà - Liste, Dizionario, ecc.) Devono anche essere istanziate o create.

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

Si ottiene la stessa eccezione per lo stesso motivo: myList stato dichiarato solo, ma nessuna istanza creata. 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 un Type raccolta:

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 generano un NRE, perché la barList è solo dichiarata, non istanziata. La creazione di un'istanza di Foo non creerà anche un'istanza della barList interna. 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) Class .

Oggetti del fornitore di dati

Lavorare con i database presenta molte opportunità per un NullReference perché ci possono essere molti oggetti ( Command , Connection , Transaction , Dataset , DataTable , DataRows ....) in uso contemporaneamente. Nota: non importa quale fornitore di dati si sta utilizzando - 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'oggetto dataset ds stato dichiarato, ma non è mai stata creata un'istanza. DataAdapter riempie un DataSet esistente, non ne crea uno. In questo caso, poiché ds è una variabile locale, l'IDE avverte che ciò potrebbe accadere:

Quando viene dichiarato come variabile di modulo / classe, come sembra essere il caso di con , il compilatore non può sapere se l'oggetto è stato creato da una procedura upstream. Non ignorare gli avvertimenti.

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 è stata creata alcuna DataTable denominata "Employee", quindi una NullReferenceException risulta provante ad accedervi. Un altro potenziale problema è supponendo che ci saranno Items che potrebbero non essere così quando l'SQL include una clausola WHERE.

Rimedio

Poiché utilizza una tabella, l'utilizzo di Tables(0) eviterà errori di ortografia. Esaminando 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 interessate che possono anche essere testate:

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

DataAdapter fornirà TableNames come mostrato nell'esempio precedente, ma non analizza i nomi dalla tabella SQL o database. Di conseguenza, 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 DataTable Class .

Percorsi oggetto / nidificati

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

Il codice sta testando solo gli Items mentre sia myFoo che Bar potrebbero anche essere Nothing. Il rimedio consiste nel testare l'intera catena o il percorso degli oggetti uno alla volta:

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

AndAlso è anche importante. I test successivi non verranno eseguiti una volta rilevata la prima condizione False . Ciò consente al codice di "perforare" in sicurezza l'oggetto (i) di un "livello" alla volta, valutando myFoo.Bar solo dopo (e se) myFoo è determinato a essere valido. Catene o percorsi di oggetti possono diventare piuttosto lunghi durante la codifica di oggetti complessi:

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

Non è possibile fare riferimento a qualcosa 'downstream' di un oggetto null . Questo vale anche per i controlli:

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

Qui, myWebBrowser o Document potrebbero essere Nothing o l'elemento formfld1 potrebbe non esistere.

Controlli dell'interfaccia utente

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 non abbia selezionato qualcosa in uno o più controlli dell'interfaccia utente. ListBox1.SelectedItempotrebbe essere Nothing, quindi ListBox1.SelectedItem.ToStringsi tradurrà in un NRE.

Rimedio

Convalidare i dati prima di utilizzarli (utilizzare anche Option Stricti 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...

Form di Visual Basic

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 segnalerà che Controlsnon esiste nel contesto corrente, o "non può fare riferimento a membri non statici". Quindi, in una certa misura, questa è una situazione VB-only. È anche complesso perché può causare una cascata di errori.

Gli array e le raccolte non possono essere inizializzati in questo modo. Questo codice di inizializzazione verrà eseguito prima che il costruttore crei Formo il Controls. Di conseguenza:

  • Gli elenchi e le raccolte saranno semplicemente vuoti
  • L'array conterrà cinque elementi di Nothing
  • Il somevarcompito determinerà un'immediata NRE perché Nulla non ha una .Textproprietà

Il riferimento agli elementi dell'array in seguito comporterà un NRE. Se lo fai Form_Load, a causa di un bug strano, l'IDE potrebbe non segnalare l'eccezione quando succede. L'eccezione verrà visualizzata più tardi quando il codice tenta di utilizzare l'array. Questa "eccezione silenziosa" è dettagliata in questo post . Per i nostri scopi, la chiave è che quando accade qualcosa di catastrofico durante la creazione di un modulo ( Sub Newo Form Loadevento), le eccezioni possono non essere segnalate, il codice esce dalla procedura e visualizza solo il modulo.

Poiché nessun altro codice nel tuo Sub Newo Form Loadevento verrà eseguito dopo l'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 questo vale per tutti i riferimenti di controllo e componente che rendono questi 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 non esistono. Questo può essere fatto Sub Newfino a quando il codice è dopo la InitializeComponentchiamata:

' 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 non può ancora essere fuori dal bosco. Tutti i controlli che si trovano in un controllo contenitore (come a GroupBoxo Panel) non saranno trovati in Me.Controls; saranno nella collezione Controls di quel Panel o GroupBox. Né verrà restituito un controllo quando il nome del controllo è errato ( "TeStBox2"). In questi casi, Nothingverrà nuovamente memorizzato in quegli elementi dell'array e verrà generato 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 Controlsraccolta 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...})

Funzione che non restituisce nulla

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 avviserà che " non tutti i percorsi restituiscono un valore e un NullReferenceExceptionrisultato può ". È possibile sopprimere l'avviso sostituendolo Exit Functioncon Return Nothing, ma ciò non risolve il problema. Tutto ciò che cerca di utilizzare il ritorno quando someCondition = Falserisulterà in una NRE:

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

Rimedio

Sostituisci Exit Functionnella funzione con Return bList. Restituire un vuoto List non equivale a ritornare Nothing. Se c'è la possibilità che un oggetto restituito possa essere Nothing, prova prima di usarlo:

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

Prova / catture implementate in modo errato

Una Prova / Catch mal implementata può nascondere dove si trova il problema e generarne 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 è il caso in cui un oggetto non viene creato come previsto, ma dimostra anche l'utilità contatore di un vuoto Catch.

C'è una virgola in più nell'SQL (dopo 'mailaddress') che risulta in un'eccezione a .ExecuteReader. Dopo Catchche non esegue nulla, Finallyprova a eseguire la pulizia, ma dal momento che non è possibile Closeun DataReaderoggetto nullo , un NullReferenceExceptionrisultato nuovo di zecca .

Un Catchblocco vuoto è il campo da gioco del diavolo. Questo OP era sconcertato perché stava ottenendo una NRE nel Finallyblocco. In altre situazioni, un vuoto Catchpuò causare qualcos'altro molto più a valle che va in tilt e ti fa 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 vuoti blocchi Try / Catch: fai in modo che il codice si blocchi in modo da poter a) identificare la causa b) identificare la posizione e c) applicare un rimedio adeguato. I blocchi Try / Catch non hanno lo scopo di nascondere le eccezioni della persona in modo univoco qualificato per risolverli - lo sviluppatore.

DBNull non è uguale a Nothing

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

La IsDBNullfunzione 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, 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
       ...

FirstOrDefaultrestituisce il primo elemento o il valore predefinito, che è Nothingper i tipi di riferimento e mai DBNull:

If getFoo IsNot Nothing Then...

controlli

Dim chk As CheckBox

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

Se CheckBoxa chkNamenon può essere trovato un (o esiste in a GroupBox), allora chksarà Nothing e tentare di fare riferimento a qualsiasi proprietà causerà un'eccezione.

Rimedio

If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...

The DataGridView

Il DGV ha alcune stranezze viste 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 lo dgvBooksha AutoGenerateColumns = True, creerà le colonne, ma non le nominerà, quindi il codice sopra riportato fallisce quando fa riferimento ad esse per nome.

Rimedio

Assegna un nome alle colonne manualmente o fai riferimento all'indice:

dgvBooks.Columns(0).Visible = True

Esempio 2: attenzione al NewRow

xlWorkSheet = xlWorkBook.Sheets("sheet1")

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

Quando il vostro DataGridViewha AllowUserToAddRowscome True(impostazione predefinita), il Cellsil vuoto / nuova riga in fondo saranno tutti contengono Nothing. La maggior parte dei tentativi di utilizzare i contenuti (ad esempio, ToString) genererà un NRE.

Rimedio

Utilizzare un For/Eachciclo e testare la IsNewRowproprietà per determinare se è l'ultima riga. 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 usi un For nciclo, modifica il conteggio delle righe o usa Exit Forquando IsNewRowè vero.

My.Settings (StringCollection)

In determinate circostanze, provare a utilizzare un oggetto dal My.Settingsquale è StringCollectionpossibile ottenere un valore NullReference la prima volta che lo si utilizza. La soluzione è la stessa, ma non così ovvia. Tenere conto:

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

Poiché VB sta gestendo 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 Impostazioni). Poiché la raccolta è (apparentemente) inizializzata quando viene aggiunto un elemento, rimane Nothingquando non ci sono elementi nell'editor Impostazioni da aggiungere.

Rimedio

Inizializza la raccolta delle impostazioni nel Loadgestore 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 Settingsraccolta deve essere inizializzata solo la prima volta che viene eseguita l'applicazione. Un rimedio alternativo consiste nell'aggiungere un valore iniziale alla tua raccolta in Project -> Impostazioni | FooBars , salva il progetto, quindi rimuovi il valore falso.

Punti chiave

Probabilmente hai dimenticato l' Newoperatore.

o

Qualcosa che hai assunto avrebbe funzionato in modo impeccabile per restituire un oggetto inizializzato al tuo codice, no.

Non ignorare gli avvisi del compilatore (mai) e utilizzare Option Strict On(sempre).

MSDN eccezione NullReference

not set to

Ho del codice e quando viene eseguito, lancia una NullReferenceException , dicendo:

Il riferimento non impostato su un'istanza di un oggetto.

Cosa significa questo e cosa posso fare per correggere questo errore?




Significa che la variabile in questione non è puntata sul nulla. Potrei generare questo in questo modo:

SqlConnection connection = null;
connection.Open();

Questo genererà l'errore perché mentre ho dichiarato la variabile " connection", non è indirizzato a nulla. Quando provo a chiamare il membro " Open", non c'è alcun riferimento da risolvere per risolvere l'errore.

Per evitare questo errore:

  1. Inizializza sempre i tuoi oggetti prima di provare a fare qualcosa con loro.
  2. Se non sei sicuro se l'oggetto è nullo, controlla con object == null.

Lo strumento di Resharper di JetBrains identificherà ogni posizione nel codice che ha la possibilità di un errore di riferimento null, consentendo di inserire un controllo Null. Questo errore è la fonte numero uno di bug, IMHO.




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/ nullper 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/ nullmanualmente, oppure hai chiamato una funzione che imposta la variabile su Nothing/ nullper te.




Se non è stato inizializzato un tipo di riferimento e si desidera impostare o leggere una delle sue proprietà, verrà generata una eccezione NullReferenceException .

Esempio:

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

Puoi semplicemente evitare questo controllando se la variabile non è nullo:

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

Per comprendere appieno perché viene generata una NullReferenceException, è importante conoscere la differenza tra tipi di valori e tipi di riferimento .

Quindi, se hai a che fare con tipi di valore , NullReferenceExceptions non può verificarsi. Anche se è necessario mantenere l'attenzione quando si tratta di tipi di riferimento !

Solo i tipi di riferimento, come suggerisce il nome, possono contenere riferimenti o punti letteralmente a nulla (o "null"). Mentre i tipi di valore contengono sempre un valore.

Tipi di riferimento (questi devono essere controllati):

  • dinamico
  • oggetto
  • stringa

Tipi di valore (puoi semplicemente ignorare questi):

  • Tipi numerici
  • Tipi integrali
  • Tipi a virgola mobile
  • decimale
  • bool
  • Strutture definite dall'utente



Stai utilizzando l'oggetto che contiene il riferimento al valore nullo. Quindi sta dando un'eccezione nulla. Nell'esempio il valore stringa è nullo e quando si verifica la 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 oggetto non impostato su un'istanza di un oggetto. a Program.Main ()




Mentre ciò che causa l'eccezione di NullReferenceExceptions e gli approcci per evitare / correggere tale eccezione sono stati risolti in altre risposte, ciò che molti programmatori non hanno ancora imparato è come debugare in modo indipendente tali eccezioni durante lo sviluppo.

In Visual Studio questo è solitamente facile grazie a Visual Studio Debugger .

Innanzitutto, assicurati che venga rilevato l'errore corretto: vedi Come consentire l'interruzione di System.NullReferenceException in VS2010? Nota 1

Quindi avviare con debug (F5) o collegare [il debugger VS] al processo in esecuzione . A volte può essere utile da usare Debugger.Break, che richiederà di avviare il debugger.

Ora, quando la NullReferenceException viene lanciata (o non gestita), il debugger si fermerà (ricorda 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 myStringvalutato null. Questo può essere verificato guardando la finestra di controllo o eseguendo espressioni nella finestra immediata .

var x = myString.Trim();

Nei casi più avanzati, come i seguenti, è necessario utilizzare una delle tecniche di cui sopra (Guarda o Immediate Windows) per ispezionare le espressioni per determinare se str1era nullo o se str2era nullo.

var x = str1.Trim() + str2.Trim();

Una volta in cui si è stato situato a due l'eccezione, di solito è banale per ragionare a ritroso per scoprire dove il valore null è stato [errato] ha introdotto -

Prendi il tempo necessario per capire la causa dell'eccezione. Esamina le espressioni nulle. Ispeziona le espressioni precedenti che potrebbero aver portato a tali espressioni nulle. Aggiungi breakpoints e passa attraverso 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, è possibile utilizzare l' opzione Break on User-Unhandled per limitare le eccezioni rilevate. Inoltre, VS2012 introduce Just My Code che raccomando di abilitare.

Se esegui 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 scelta che vengono lanciate all'esterno di My Code e non passano attraverso My Code




Un altro caso generale in cui si potrebbe ricevere questa eccezione riguarda le classi di derisione durante i test unitari. A prescindere dal framework di simulazione che viene utilizzato, è necessario assicurarsi che tutti i livelli appropriati della gerarchia delle classi vengano opportunamente derisi. In particolare, tutte le proprietà di HttpContextcui fanno riferimento il codice in prova devono essere derise.

Vedi " NullReferenceException generata durante il test di AuthorizationAttribute personalizzato " per un esempio un po 'prolisso.




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 è l'applicazione di un progetto per contratto nel codice. Ciò significa che è necessario impostare gli invarianti di classe e / o anche le precondizioni di funzione / metodo e le post- condizioni sul proprio sistema durante lo sviluppo.

In breve, gli invarianti di classe assicurano che nella classe ci saranno alcuni vincoli che non verranno violati nell'uso normale (e quindi la classe non entrerà in uno stato incoerente). Le precondizioni significano che i dati forniti come input a una funzione / metodo devono seguire alcuni vincoli impostati e non violarli mai , e le 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, quindi la progettazione per contratto viene verificata nella pratica in modalità di debug, mentre viene disabilitata nelle versioni , per massimizzare le prestazioni del sistema sviluppato.

In questo modo, puoi evitare NullReferenceExceptioncasi che sono risultati dalla violazione dei vincoli impostati. Ad esempio, se si utilizza una proprietà oggetto Xin una classe e successivamente si tenta di richiamare uno dei suoi metodi e Xha un valore nullo, questo porterà a NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

Ma se si imposta "proprietà X non deve mai avere un valore nullo" come precondizione del metodo, è possibile impedire lo scenario descritto prima:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

Per questa causa, esiste il progetto Contratti di codice per le applicazioni .NET.

In alternativa, la progettazione per contratto può essere applicata utilizzando le assertions .

AGGIORNAMENTO: Vale la pena ricordare che il termine fu coniato da Bertrand Meyer in connessione con il suo design del linguaggio di programmazione Eiffel .




TL; DR: prova a usare Html.Partialinvece diRenderpage

Stavo diventando Object reference not set to an instance of an objectquando ho provato a rendere una vista all'interno di una vista inviando un modello, come questo:

@{
    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.Partialiniziare era perché Visual Studio a volte genera delle linee ondulate che sembrano errori Html.Partialse si trova all'interno di un foreachciclo costruito in modo diverso , anche se non è realmente 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 ero in grado di eseguire l'applicazione senza problemi con questo "errore". Sono stato in grado di sbarazzarsi dell'errore cambiando la struttura del foreachloop per assomigliare a questo:

@foreach(var M in MyEntities){
    ...
}

Anche se ho la sensazione che fosse perché Visual Studio stava fraintendendo la e commerciale e le parentesi.




È possibile correggere NullReferenceException in modo pulito utilizzando Operatori Null-condizionali in c # 6 e scrivere meno codice per gestire i controlli Null.

Viene utilizzato per verificare null prima di eseguire un'operazione di accesso (?.) O indice (? [).

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à nullo quando p è nullo o quando p.Spouse è nullo.

Altrimenti, al nome della variabile verrà assegnato il valore di p.Spouse.FirstName.

Per ulteriori dettagli: operatori con condizioni nulle




È interessante notare che nessuna delle risposte di questa pagina menziona i due casi limite, spero che nessuno se la metta se li aggiungo:

Edge case n. 1: accesso concorrente a un dizionario

I dizionari generici in .NET non sono thread-safe e a volte possono lanciare NullReferenceo anche (più frequenti) a KeyNotFoundExceptionquando si tenta di accedere a una chiave da due thread simultanei. L'eccezione è abbastanza fuorviante in questo caso.

Edge case n. 2: codice non sicuro

Se a NullReferenceExceptionviene lanciato un unsafecodice, puoi guardare le variabili del puntatore e controllarle IntPtr.Zeroo qualcosa del genere. Qual è la stessa cosa ("eccezione puntatore nullo"), ma nel codice non sicuro, le variabili vengono spesso convertite in tipi di valore / matrici, ecc. E sbatti la testa contro il muro, chiedendosi come un valore può lanciare questo eccezione.

(Un altro motivo per non usare codice non sicuro a meno che non ne abbiate bisogno, a proposito)




Bene, in termini semplici:

Stai tentando di accedere a un oggetto che non è stato creato o che attualmente non è in memoria.

Quindi, come affrontare questo:

  1. Esegui il debug e lascia che il debugger si interrompa ... Ti porterà direttamente alla variabile che è rotta ... Ora il tuo compito è quello di correggere semplicemente questo .. Usando la nuova parola chiave nella posizione appropriata.

  2. Se è causato da alcuni comandi del database perché l'oggetto non è presente, tutto ciò che devi fare è eseguire un controllo nullo e gestirlo:

    if (i == null) {
        // Handle this
    }
    
  3. Il più difficile ... se il GC già raccolto l'oggetto ... Questo in genere si verifica se stai cercando di trovare un oggetto usando le stringhe ... Cioè, trovandolo per nome dell'oggetto allora potrebbe succedere che il GC potrebbe già pulito ... Questo è difficile da trovare e diventerà un bel problema ... Un modo migliore per affrontarlo è fare controlli nulli ovunque sia necessario durante il processo di sviluppo. Questo ti farà risparmiare molto tempo.

Trovando per nome intendo che alcuni framework consentono di utilizzare oggetti con stringhe e il codice potrebbe essere simile a questo: FindObject ("ObjectName");




Letteralmente, il modo più semplice per risolvere un NullReferenceExeption ha due possibilità. Se hai un GameObject ad esempio con uno script allegato e una variabile chiamata rb (rigidbody) questa variabile inizierà a zero quando inizi la partita.
Questo è il motivo per cui ottieni un'eccezione NullReference perché il computer non ha dati memorizzati in quella variabile.

Userò una variabile RigidBody come esempio.
Siamo in grado di aggiungere dati davvero facilmente in pochi modi:

  1. Aggiungi un oggetto RigidBody al tuo oggetto con AddComponent> Physics> Rigidbody
    Quindi entra nello script e digita rb = GetComponent<Rigidbody>();
    Questa riga di codice funziona meglio sotto le tue Start()o Awake()funzioni.
  2. È possibile aggiungere un componente a livello di codice e assegnare la variabile allo stesso tempo con una riga di codice: 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 dichiarazione della classe (lo spazio sotto tutti i tuoi usi).
Divertiti e divertiti a creare giochi!




Se si riceve questo messaggio durante il salvataggio o la compilazione della build, è sufficiente chiudere tutti i file e quindi aprire qualsiasi file da compilare e salvare.

Per me il motivo era che avevo rinominato il file e il vecchio file era ancora aperto.




Significa che stai cercando di manipolare qualcosa che ha un riferimento ma non ancora inizializzato.
La prima cosa da fare qui è controllare ogni istanza creata.

Usa punti di interruzione, guarda, controlla i tuoi valori varibali.
Segui la traccia dello stack e cerca la riga e la colonna esatte che creano problemi




Related