c# - unity - system.nullreferenceexception como resolver




O que é um NullReferenceException e como corrijo isso? (20)

Exceção NullReference - Visual Basic

O NullReference Exception para Visual Basic não é diferente daquele em C # . Afinal, ambos estão relatando a mesma exceção definida no .NET Framework que ambos usam. Causas exclusivas do Visual Basic são raras (talvez apenas uma).

Essa resposta usará termos, sintaxe e contexto do Visual Basic. Os exemplos usados ​​vêm de um grande número de perguntas anteriores sobre estouro de pilha. Isso é para maximizar a relevância usando os tipos de situações frequentemente vistas em postagens. Um pouco mais de explicação também é fornecido para aqueles que podem precisar dele. Um exemplo semelhante ao seu é muito provavelmente listado aqui.

Nota:

  1. Isso é baseado em conceito: não há código para você colar em seu projeto. O objetivo é ajudá-lo a entender o que causa um NRE ( NullReferenceException ), como encontrá-lo, como corrigi-lo e como evitá-lo. Um NRE pode ser causado de várias maneiras, então é improvável que esse seja seu único encontro.
  2. Os exemplos (de postagens de estouro de pilha) nem sempre mostram a melhor maneira de fazer algo em primeiro lugar.
  3. Normalmente, o remédio mais simples é usado.

Significado Básico

A mensagem "Objeto não definido para uma instância de Objeto" significa que você está tentando usar um objeto que não foi inicializado. Isso se resume a um destes:

  • Seu código declarou uma variável de objeto, mas ela não foi inicializada (crie uma instância ou " instancie ")
  • Algo que o seu código assumiu que iria inicializar um objeto, não
  • Possivelmente, outro código invalidou prematuramente um objeto ainda em uso

Encontrando a causa

Desde que o problema é uma referência de objeto que é Nothing , a resposta é examiná-los para descobrir qual deles. Em seguida, determine por que não é inicializado. Mantenha o mouse sobre as várias variáveis ​​e o Visual Studio (VS) mostrará seus valores - o culpado será Nothing .

Você também deve remover qualquer bloco Try / Catch do código relevante, especialmente aqueles onde não há nada no bloco Catch. Isso fará com que seu código trave quando tentar usar um objeto que é Nothing . Isso é o que você quer, pois identificará a localização exata do problema e permitirá identificar o objeto que está causando o problema.

Uma MsgBox no Catch que exibe Error while... será de pouca ajuda. Esse método também leva a perguntas muito ruins sobre estouro de pilha, porque você não pode descrever a exceção real, o objeto envolvido ou até mesmo a linha de código em que isso acontece.

Você também pode usar a Locals Window ( Debug -> Windows -> Locals ) para examinar seus objetos.

Uma vez que você sabe o que e onde está o problema, geralmente é mais fácil de corrigir e mais rápido do que postar uma nova pergunta.

Veja também:

Exemplos e remédios

Objetos de Classe / Criando uma Instância

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

O problema é que Dim não cria um objeto CashRegister; ele apenas declara uma variável chamada reg desse tipo. Declarar uma variável de objeto e criar uma instância são duas coisas diferentes.

Remédio

O operador New pode ser usado para criar a instância quando você a declara:

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

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

Quando é apropriado criar a instância mais tarde:

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

Nota: Não use Dim novamente em um procedimento, incluindo o construtor ( Sub New ):

Private reg As CashRegister
'...

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

Isto irá criar uma variável local , reg , que existe apenas nesse contexto (sub). A variável reg com o Scope nível de módulo que você usará em qualquer outro lugar permanece como Nothing .

Ausente o operador New é a causa número 1 de NullReference Exceptions de referência NullReference Exceptions observadas nas perguntas sobre estouro de pilha revisadas.

Visual Basic tenta tornar o processo claro repetidamente usando New : usando o New operador cria um novo objeto e chama Sub New - o construtor - onde seu objeto pode executar qualquer outra inicialização.

Para ser claro, Dim (ou Private ) apenas declara uma variável e seu Type . O escopo da variável - se existe para todo o módulo / classe ou é local para um procedimento - é determinado por onde é declarado. Private | Friend | Public Private | Friend | Public define o nível de acesso, não o Escopo .

Para mais informações, veja:

Matrizes

Arrays também devem ser instanciados:

Private arr as String()

Este array só foi declarado, não criado. Existem várias maneiras de inicializar uma matriz:

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 partir do VS 2010, ao inicializar um array local usando um literal e Option Infer , os elementos As <Type> e New são opcionais:

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}

O tipo de dados e o tamanho da matriz são inferidos a partir dos dados que estão sendo atribuídos. Declarações de nível de classe / módulo ainda requerem As <Type> com Option Strict :

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

Exemplo: array de objetos de classe

Dim arrFoo(5) As Foo

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

A matriz foi criada, mas os objetos Foo nela não foram.

Remédio

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

Usando uma List(Of T) tornará muito difícil ter um elemento sem um objeto válido:

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

Para mais informações, veja:

Listas e Coleções

Coleções .NET (das quais existem muitas variedades - Listas, Dicionário, etc.) também devem ser instanciadas ou criadas.

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

Você obtém a mesma exceção pelo mesmo motivo - myList foi declarado apenas, mas nenhuma instância foi criada. O remédio é o mesmo:

myList = New List(Of String)

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

Um descuido comum é uma classe que usa uma coleção.

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

Qualquer procedimento resultará em um NRE, porque barList é declarado apenas, não instanciado. Criar uma instância do Foo também não criará uma instância da barList interna. Pode ter sido a intenção de fazer isso no construtor:

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

Como antes, isso está incorreto:

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

Para mais informações, consulte Classe de List(Of T) .

Objetos do Provedor de Dados

Trabalhar com bancos de dados apresenta muitas oportunidades para um NullReference, pois pode haver muitos objetos ( Command , Connection , Transaction , Dataset , DataTable , DataRows ....) em uso de uma só vez. Nota: Não importa qual provedor de dados você está usando - MySQL, SQL Server, OleDB, etc. - os conceitos são os mesmos.

Exemplo 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

Como antes, o objeto ds Dataset foi declarado, mas uma instância nunca foi criada. O DataAdapter preencherá um DataSet existente e não criará um. Nesse caso, como ds é uma variável local, o IDE avisa que isso pode acontecer:

Quando declarada como uma variável de nível de módulo / classe, como parece ser o caso com con , o compilador não pode saber se o objeto foi criado por um procedimento upstream. Não ignore os avisos.

Remédio

Dim ds As New DataSet

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

Um erro de digitação é um problema aqui: Employees x Employee . Não havia DataTable chamado "Employee" criado, portanto, um NullReferenceException resultados tentando acessá-lo. Outro problema potencial é supor que haverá Items que podem não ser assim quando o SQL inclui uma cláusula WHERE.

Remédio

Como isso usa uma tabela, o uso de Tables(0) evitará erros de ortografia. Examinar Rows.Count também pode ajudar:

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 é uma função que retorna o número de Rows afetadas que também podem ser testadas:

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

Exemplo 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

O DataAdapter fornecerá TableNames conforme mostrado no exemplo anterior, mas não analisará os nomes da tabela SQL ou do banco de dados. Como resultado, ds.Tables("TICKET_RESERVATION") referência a uma tabela inexistente.

O Remedy é o mesmo, referencia a tabela por índice:

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

Veja também Classe DataTable .

Caminhos de Objetos / Aninhados

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

O código está testando apenas Items enquanto o myFoo e o Bar também podem ser Nothing. O remédio é testar toda a cadeia ou caminho de objetos, um de cada vez:

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

AndAlso é importante. Os testes subseqüentes não serão executados quando a primeira condição False for encontrada.Isso permite que o código "perfure" com segurança no (s) objeto (s), um "nível" de cada vez, avaliando myFoo.Barsomente após (e se) myFooser determinado como válido. Cadeias de objetos ou caminhos podem ficar bastante longos ao codificar objetos complexos:

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

Não é possível fazer referência a qualquer coisa "downstream" de um nullobjeto. Isso também se aplica aos controles:

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

Aqui, myWebBrowserou Documentpoderia ser nada ou oformfld1 elemento pode não existir.

Controles da interface do usuário

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)

Entre outras coisas, esse código não prevê que o usuário pode não ter selecionado algo em um ou mais controles da interface do usuário. ListBox1.SelectedItembem pode ser Nothing, então ListBox1.SelectedItem.ToStringirá resultar em um NRE.

Remédio

Valide os dados antes de usá-los (use também os Option Strictparâmetros 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

Alternativamente, você pode usar (ComboBox5.SelectedItem IsNot Nothing) AndAlso...

Formulários 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

Esta é uma maneira bastante comum de obter um NRE. Em C #, dependendo de como ele é codificado, o IDE informará que Controlsnão existe no contexto atual ou "não pode referenciar um membro não estático". Então, até certo ponto, esta é uma situação somente VB. Também é complexo porque pode resultar em uma falha na cascata.

Os arrays e coleções não podem ser inicializados dessa maneira. Este código de inicialização será executado antes que o construtor crie o Formou o Controls. Como um resultado:

  • Listas e Coleção simplesmente ficarão vazias
  • O Array conterá cinco elementos de Nothing
  • A somevaratribuição resultará em um NRE imediato porque Nada não tem uma .Textpropriedade

Referenciar elementos de matriz posteriormente resultará em um NRE. Se você fizer isso Form_Load, devido a um bug estranho, o IDE pode não relatar a exceção quando isso acontecer. A exceção aparecerá mais tarde quando seu código tentar usar a matriz. Essa "exceção silenciosa" é detalhada neste post . Para os nossos propósitos, a chave é que quando algo catastrófico acontece ao criar um formulário ( Sub NewouForm Load evento), as exceções podem não ser relatadas, o código sai do procedimento e apenas exibe o formulário.

Desde nenhum outro código em seu Sub Newou Form Loadevento será executado após o NRE, muitas outras coisas podem ser deixadas não inicializado.

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

Observe que isso se aplica a todas e quaisquer referências de componentes e controles, tornando-as ilegais onde estão:

Public Class Form1

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

Remédio Parcial

É curioso que VB não fornecer um aviso, mas o remédio é declarar os recipientes ao nível do formulário, mas inicializar -los em manipulador de eventos load forma quando os controles não existe. Isso pode ser feito Sub Newcontanto que seu código esteja após a InitializeComponentchamada:

' 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

O código da matriz pode não estar fora da floresta ainda. Quaisquer controles que estão em um controle de contêiner (como um GroupBoxou Panel) não serão encontrados em Me.Controls; eles estarão na coleção Controls desse Panel ou GroupBox. Nem um controle será retornado quando o nome do controle estiver incorreto ( "TeStBox2"). Em tais casos,Nothing será novamente armazenado nesses elementos da matriz e ocorrerá um NRE quando você tentar referenciá-lo.

Estes devem ser fáceis de encontrar, agora que você sabe o que está procurando:

"Button2" reside em um Panel

Remédio

Em vez de referências indiretas por nome usando a Controlscoleção do formulário , use a referência de controle:

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

Função Retornando Nada

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

Este é um caso em que o IDE irá avisá-lo que ' nem todos os caminhos retornam um valor e um NullReferenceExceptionresultado '. Você pode suprimir o aviso, substituindo Exit Functionpor Return Nothing, mas isso não resolve o problema. Qualquer coisa que tente usar o retorno quando someCondition = Falseresultará em um NRE:

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

Remédio

Substitua Exit Functiona função por Return bList. Retornar um vazio List não é o mesmo que retornar Nothing. Se houver uma chance de que um objeto retornado possa ser Nothing, teste antes de usá-lo:

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

Tentativa / captura mal implementada

Um Try / Catch mal implementado pode esconder onde está o problema e resultar em novos:

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

Este é um caso de um objeto não sendo criado como esperado, mas também demonstra a utilidade do contador de um vazio Catch.

Há uma vírgula extra no SQL (após 'mailaddress') que resulta em uma exceção em .ExecuteReader. Depois que o Catchfaz nada, Finallytenta realizar a limpeza, mas desde que você não pode Closeum DataReaderobjeto nulo , uma nova marcaNullReferenceException resultado.

Um Catchbloco vazio é o playground do diabo. Este OP ficou perplexo porque ele estava recebendo um NRE no Finallybloco. Em outras situações, um vazio Catchpode resultar em algo muito mais a jusante, fazendo com que você gaste tempo procurando as coisas erradas no lugar errado para o problema. (A "exceção silenciosa" descrita acima fornece o mesmo valor de entretenimento.)

Remédio

Não use blocos Try / Catch vazios - deixe o código travar para que você possa a) identificar a causa b) identificar o local ec) aplicar um remédio adequado. Blocos Try / Catch não se destinam a esconder exceções da pessoa exclusivamente qualificada para corrigi-los - o desenvolvedor.

DBNull não é o mesmo que nada

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

A IsDBNullfunção é usada para testar se um valor é igual a System.DBNull: No MSDN:

O valor System.DBNull indica que o objeto representa dados ausentes ou inexistentes. DBNull não é o mesmo que Nothing, o que indica que uma variável ainda não foi inicializada.

Remédio

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

Como antes, você pode testar Nothing e, em seguida, por um valor específico:

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

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

FirstOrDefaultretorna o primeiro item ou o valor padrão, que é Nothingpara tipos de referência e nunca DBNull:

If getFoo IsNot Nothing Then...

Controles

Dim chk As CheckBox

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

Se um CheckBoxcom chkNamenão puder ser encontrado (ou existir em um GroupBox), então chkserá Nothing e tentar referenciar qualquer propriedade resultará em uma exceção.

Remédio

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

O DataGridView

A DGV tem algumas peculiaridades vistas 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 dgvBookstiver AutoGenerateColumns = True, ele criará as colunas, mas não as nomeará, portanto, o código acima falhará quando fizer referência a elas por nome.

Remédio

Nomeie as colunas manualmente ou referência por índice:

dgvBooks.Columns(0).Visible = True

Exemplo 2 - Cuidado com o 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 o seu DataGridViewtem AllowUserToAddRowscomo True(o padrão), o Cellsna linha em branco / novo na parte inferior conterá todos Nothing. A maioria das tentativas de usar o conteúdo (por exemplo, ToString) resultará em um NRE.

Remédio

Use um For/Eachloop e teste a IsNewRowpropriedade para determinar se é a última linha. Isso funciona se AllowUserToAddRowsé verdade ou não:

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

Se você usar um For nloop, modifique a contagem de linhas ou use Exit Forwhen IsNewRowis true.

My.Settings (StringCollection)

Em determinadas circunstâncias, tentar usar um item do My.Settingsqual é um StringCollectionpode resultar em um NullReference na primeira vez que você usá-lo. A solução é a mesma, mas não tão óbvia. Considerar:

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

Como o VB está gerenciando as Configurações para você, é razoável esperar que ele inicialize a coleção. Será, mas somente se você adicionou anteriormente uma entrada inicial para a coleção (no editor de configurações). Como a coleção é (aparentemente) inicializada quando um item é adicionado, ele permanece Nothingquando não há itens no Editor de configurações para adicionar.

Remédio

Inicialize a coleção de configurações no Loadmanipulador de eventos do formulário , se / quando necessário:

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

Normalmente, a Settingscoleção só precisará ser inicializada na primeira vez que o aplicativo for executado. Uma solução alternativa é adicionar um valor inicial à sua coleção em Projeto -> Configurações | FooBars , salve o projeto e remova o valor falso.

Pontos chave

Você provavelmente esqueceu o Newoperador.

ou

Algo que você assumiu que seria executado de forma impecável para retornar um objeto inicializado ao seu código, não o fez.

Não ignore os avisos do compilador (nunca) e use Option Strict On(sempre).

Exceção do MSDN NullReference

Eu tenho algum código e quando ele é executado, ele lança um NullReferenceException , dizendo:

Referência de objeto não definida para uma instância de um objeto.

O que isso significa e o que posso fazer para corrigir esse erro?


Qual é a causa?

Linha de fundo

Você está tentando usar algo que é null (ou Nothing em VB.NET). Isso significa que você pode defini-lo como null ou nunca defini-lo para nada.

Como qualquer outra coisa, null é transmitido. Se for null no método "A", pode ser que o método "B" tenha passado um null para o método "A".

null pode ter diferentes significados:

  1. Variáveis ​​de objeto que não são inicializadas e, portanto, não apontam para nada. Nesse caso, se você acessar propriedades ou métodos de tais objetos, isso causará um NullReferenceException .
  2. O desenvolvedor está usando null intencionalmente para indicar que não há nenhum valor significativo disponível. Note que o C # tem o conceito de tipos de dados anuláveis ​​para variáveis ​​(como tabelas de banco de dados podem ter campos anuláveis) - você pode atribuir null a eles para indicar que não há valor armazenado nele, por exemplo, int? a = null; int? a = null; onde o ponto de interrogação indica que é permitido armazenar null na variável a . Você pode verificar isso com if (a.HasValue) {...} ou com if (a==null) {...} . Variáveis ​​anuláveis, como neste exemplo, permitem acessar o valor via a.Value explicitamente ou da mesma forma normal via a .
    Observe que acessá-lo via a.Value gera um InvalidOperationException vez de um NullReferenceException se a for null - você deve fazer a verificação antecipadamente, ou seja, se você tiver outra variável anulável para dentro int b; então você deve fazer atribuições como if (a.HasValue) { b = a.Value; } if (a.HasValue) { b = a.Value; } ou menor if (a != null) { b = a; } if (a != null) { b = a; } .

O restante deste artigo entra em mais detalhes e mostra erros que muitos programadores costumam fazer que podem levar a um NullReferenceException .

Mais especificamente

O tempo de execução lançando um NullReferenceException sempre significa a mesma coisa: você está tentando usar uma referência e a referência não é inicializada (ou já foi inicializada, mas não é mais inicializada).

Isso significa que a referência é null e você não pode acessar membros (como métodos) por meio de uma referência null . O caso mais simples:

string foo = null;
foo.ToUpper();

Isso lançará um NullReferenceException na segunda linha porque você não pode chamar o método de instância ToUpper() em uma referência de string apontando para null .

Depuração

Como você encontra a fonte de um NullReferenceException ? Além de observar a própria exceção, que será lançada exatamente no local onde ela ocorre, as regras gerais de depuração do Visual Studio se aplicam: coloque pontos de interrupção estratégicos e inspecione suas variáveis , passando o mouse sobre seus nomes, abrindo um ( Quick) Assista janela ou usando os vários painéis de depuração como Locals e Autos.

Se você quiser descobrir onde a referência está ou não definida, clique com o botão direito no nome e selecione "Localizar todas as referências". Você pode então colocar um ponto de interrupção em todos os locais encontrados e executar seu programa com o depurador anexado. Toda vez que o depurador quebrar em tal ponto de interrupção, você precisará determinar se espera que a referência seja não nula, inspecione a variável e verifique se ela aponta para uma instância quando você espera.

Seguindo o fluxo do programa dessa maneira, você pode encontrar o local onde a instância não deve ser nula e por que ela não está configurada corretamente.

Exemplos

Alguns cenários comuns em que a exceção pode ser lançada:

Genérico

ref1.ref2.ref3.member

Se ref1 ou ref2 ou ref3 forem nulos, você obterá um NullReferenceException . Se você quiser resolver o problema, descubra qual é nulo reescrevendo a expressão para seu equivalente mais simples:

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

Especificamente, em HttpContext.Current.User.Identity.Name , o HttpContext.Current pode ser nulo ou a propriedade User pode ser nula ou a propriedade Identity pode ser nula.

Indireto

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 você quiser evitar a referência nula child (Person), poderá inicializá-la no construtor do objeto pai (Book).

Inicializadores de Objetos Aninhados

O mesmo se aplica aos inicializadores de objeto aninhados:

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

Isso se traduz em

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

Enquanto a new palavra-chave é usada, ela cria apenas uma nova instância do Book , mas não uma nova instância de Person , portanto, a propriedade Author ainda é null .

Inicializadores de coleções aninhadas

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

Os inicializadores de coleção aninhada se comportam da mesma maneira:

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

Isso se traduz em

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

A new Person só cria uma instância de Person , mas a coleção Books ainda é null . A sintaxe do inicializador de coleção não cria uma coleção para p1.Books , ela só é convertida para as p1.Books.Add(...) .

Matriz

int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.

Elementos de matriz

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.

Matrizes irregulares

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.

Coleção / Lista / Dicionário

Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
                               // There is no Dictionary to perform the lookup.

Variável de faixa (indireta / diferida)

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.

Eventos

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

Convenções de nomenclatura incorretas:

Se você nomeou campos de maneira diferente dos locais, talvez tenha percebido que nunca inicializou o campo.

public class Form1 {
    private Customer customer;

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

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

Isso pode ser resolvido seguindo a convenção para prefixar campos com um sublinhado:

private Customer _customer;

Ciclo de vida da página ASP.NET:

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

Valores da Sessão ASP.NET

// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();

Modelos de visualização vazia da ASP.NET MVC

Se a exceção ocorrer ao fazer referência a uma propriedade de @Model em uma visualização do ASP.NET MVC, você precisará entender que o Model é definido em seu método de ação quando você return uma visualização. Quando você retorna um modelo vazio (ou propriedade de modelo) de seu controlador, a exceção ocorre quando as visualizações o acessam:

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

Ordem de Criação e Eventos do Controle WPF

Os controles do WPF são criados durante a chamada para InitializeComponent na ordem em que aparecem na árvore visual. Um NullReferenceException será gerado no caso de controles criados antecipadamente com manipuladores de eventos, etc., que são acionados durante o InitializeComponent que fazem referência a controles criados recentemente.

Por exemplo :

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

Aqui comboBox1 é criado antes de label1 . Se comboBox1_SelectionChanged tentar referenciar `label1, ele ainda não terá sido criado.

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

Alterar a ordem das declarações no XAML (ou seja, listar label1 antes de comboBox1 , ignorando os problemas da filosofia de design, pelo menos resolveria o NullReferenceException aqui.

Elenco com as

var myThing = someObject as Thing;

Isso não lança um InvalidCastException, mas retorna um valor null quando o elenco falha (e quando someObject é nulo). Então, fique ciente disso.

LINQ FirstOrDefault () e SingleOrDefault ()

As versões simples First() e Single() lançam exceções quando não há nada. As versões "OrDefault" retornam null nesse caso. Então, fique ciente disso.

para cada

foreach lança quando você tenta iterar coleção nula. Geralmente causado por resultado null inesperado de métodos que retornam coleções.

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

Exemplo mais realista - selecione nós do documento XML. Será lançado se os nós não forem encontrados, mas a depuração inicial mostra que todas as propriedades são válidas:

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

Maneiras de evitar

Explicitamente, verifique se há null e ignore os valores nulos.

Se você espera que a referência às vezes seja nula, é possível verificar se ela é null antes de acessar os membros da instância:

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

Explicitamente, verifique se há null e forneça um valor padrão.

Os métodos que você espera retornar uma instância podem retornar null , por exemplo, quando o objeto que está sendo procurado não pode ser encontrado. Você pode escolher retornar um valor padrão quando este for o caso:

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

Explicitamente, verifique se há null nas chamadas de método e lance uma exceção personalizada.

Você também pode lançar uma exceção personalizada, apenas para pegá-lo no código de chamada:

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

Use Debug.Assert se um valor nunca deve ser null , para capturar o problema antes que a exceção ocorra.

Quando você sabe durante o desenvolvimento que um método talvez pode, mas nunca deve retornar null , você pode usar Debug.Assert() para quebrar o mais rápido possível quando ocorrer:

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

Embora essa verificação não acabe em sua compilação de release , fazendo com que ela apresente o NullReferenceException novamente quando o book == null runtime no modo de liberação.

Use GetValueOrDefault() para tipos de valor anuláveis ​​para fornecer um valor padrão quando eles são 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

Use o operador de coalescência nulo: ?? [C #] ou If() [VB].

A abreviação para fornecer um valor padrão quando um null é encontrado:

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

Use o operador de condição nulo ?. ou ?[x] para matrizes (disponível em C # 6 e VB.NET 14):

Isso também é chamado de operador de navegação segura ou Elvis (após sua forma). Se a expressão no lado esquerdo do operador for nula, o lado direito não será avaliado e será retornado nulo. Isso significa casos assim:

var title = person.Title.ToUpper();

Se a pessoa não tiver um título, isso lançará uma exceção porque está tentando chamar o ToUpper em uma propriedade com um valor nulo.

No C # 5 e abaixo, isso pode ser guardado com:

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

Agora a variável de título será nula em vez de lançar uma exceção. C # 6 introduz uma sintaxe mais curta para isso:

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

Isso resultará na variável de título sendo null e a chamada para ToUpper não será feita se person.Title for null .

Claro, você ainda tem que verificar o title para null ou usar o operador de condição nula junto com o operador de coalescência nulo ( ?? ) para fornecer um valor padrão:

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

Da mesma forma, para matrizes, você pode usar ?[i] seguinte maneira:

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

Isso fará o seguinte: Se myIntArray for nulo, a expressão retornará null e você poderá verificá-la com segurança. Se contiver uma matriz, fará o mesmo que: elem = myIntArray[i]; e retorna o i- ésimo elemento.

Técnicas especiais para depuração e correção de derefs nulos em iteradores

C # suporta "blocos iteradores" (chamados "geradores" em outras linguagens populares). Exceções de cancelamento de referência nulas podem ser particularmente difíceis de depurar em blocos de iterador devido à execução adiada:

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 o whatever resultar em null , o MakeFrob irá lançar. Agora, você pode pensar que a coisa certa a fazer é esta:

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

Por que isso está errado? Porque o bloco iterador realmente não funciona até o foreach ! A chamada para GetFrobs simplesmente retorna um objeto que, quando iterado , executará o bloco do iterador.

Ao gravar uma verificação nula como essa, você evita a remoção de referência nula, mas move a exceção do argumento nulo para o ponto da iteração , não para o ponto da chamada , e isso é muito confuso para depuração .

A correção correta é:

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

Ou seja, crie um método auxiliar privado que tenha a lógica do bloco do iterador e um método de superfície pública que faça a verificação nula e retorne o iterador. Agora quando GetFrobs é chamado, a verificação nula acontece imediatamente e, em seguida, GetFrobsForReal executado quando a seqüência é iterada.

Se você examinar a fonte de referência do LINQ to Objects, verá que essa técnica é usada por toda parte. É um pouco mais complicado escrever, mas facilita muito a depuração de erros de nulidade. Otimize seu código para a conveniência do chamador, não a conveniência do autor .

Uma nota sobre desreferências nulas em código não seguro

C # tem um modo "inseguro" que é, como o nome indica, extremamente perigoso porque os mecanismos de segurança normais que fornecem segurança de memória e segurança de tipo não são aplicados. Você não deve escrever códigos inseguros a menos que tenha uma compreensão profunda e profunda de como a memória funciona .

No modo inseguro, você deve estar ciente de dois fatos importantes:

  • desreferenciando um ponteiro nulo produz a mesma exceção como desreferenciando uma referência nula
  • desreferência de um ponteiro não nulo inválido pode produzir essa exceção em algumas circunstâncias

Para entender por que isso acontece, é útil entender como o .NET produz exceções de desreferências nulas em primeiro lugar. (Esses detalhes se aplicam ao .NET em execução no Windows; outros sistemas operacionais usam mecanismos semelhantes.)

A memória é virtualizada no Windows; cada processo obtém um espaço de memória virtual de muitas "páginas" de memória que são rastreadas pelo sistema operacional. Cada página de memória tem sinalizadores que determinam como ela pode ser usada: ler, gravar, executar e assim por diante. A página mais baixa está marcada como "produzir um erro se alguma vez for usada de alguma forma".

Tanto um ponteiro nulo quanto uma referência nula em C # são representados internamente como o número zero e, portanto, qualquer tentativa de desreferencia-lo em seu armazenamento de memória correspondente faz com que o sistema operacional produza um erro. O tempo de execução do .NET, em seguida, detecta esse erro e o transforma na exceção de desreferenciação nula.

É por isso que desreferenciando um ponteiro nulo e uma referência nula produz a mesma exceção.

E quanto ao segundo ponto? A desreferência de qualquer ponteiro inválido que caia na página mais baixa da memória virtual causa o mesmo erro do sistema operacional e, portanto, a mesma exceção.

Por que isso faz sentido? Bem, suponha que tenhamos uma estrutura contendo dois inteiros e um ponteiro não gerenciado igual a nulo. Se tentarmos cancelar a referência do segundo int na estrutura, o CLR não tentará acessar o armazenamento no local zero; ele acessará o armazenamento no local quatro. Mas, logicamente, isso é uma desreferência nula porque estamos chegando a esse endereço por meio do nulo.

Se você estiver trabalhando com código não seguro e receber uma exceção de cancelamento de referência nula, apenas esteja ciente de que o ponteiro incorreto não precisa ser nulo. Pode ser qualquer local na página inferior e essa exceção será produzida.


TL; DR: Tente usar em Html.Partialvez deRenderpage

Eu estava recebendo Object reference not set to an instance of an objectquando eu tentei renderizar uma View dentro de uma View, enviando-lhe um modelo, como este:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

A depuração mostrou que o modelo era nulo dentro do MyOtherView. Até que eu mudei para:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

E funcionou.

Além disso, o motivo pelo qual eu não tive Html.Partialque começar foi porque o Visual Studio às vezes lança linhas sinistras com aparência de erro Html.Partialse estiver dentro de um foreachloop construído de maneira diferente , mesmo que não seja realmente um erro:

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

Mas eu era capaz de executar o aplicativo sem problemas com este "erro". Consegui me livrar do erro alterando a estrutura do foreachloop para ficar assim:

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

Embora eu tenha a sensação de que era porque o Visual Studio estava interpretando mal o e comercial e os colchetes.


A linha de erro "Referência de objeto não definida para uma instância de um objeto" indica que você não atribuiu o objeto de instância a uma referência de objeto e ainda está acessando propriedades / métodos desse objeto.

por exemplo: digamos que você tenha uma classe chamada myClass e contenha uma propriedade prop1.

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

Agora você está acessando este prop1 em alguma outra classe como abaixo:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

A linha acima gera erro porque a referência da classe myClass é declarada mas não instanciada ou uma instância do objeto não é atribuída ao referecne dessa classe.

Para corrigir isso, você deve instanciar (atribuir objeto à referência dessa classe).

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

Bem, em termos simples:

Você está tentando acessar um objeto que não é criado ou não está na memória no momento.

Então, como lidar com isso:

  1. Depure e deixe o depurador quebrar ... Ele irá diretamente levá-lo para a variável que está quebrada ... Agora, sua tarefa é simplesmente corrigir isso ... Usando a nova palavra-chave no local apropriado.

  2. Se isso é causado em alguns comandos do banco de dados porque o objeto não está presente, tudo o que você precisa fazer é fazer uma verificação nula e manipulá-lo:

    if (i == null) {
        // Handle this
    }
  3. O mais difícil .. se o GC já coletou o objeto ... Isso geralmente ocorre se você está tentando encontrar um objeto usando strings ... Ou seja, encontrando-o pelo nome do objeto, então pode acontecer que o GC já possa limpo ... Isso é difícil de encontrar e se tornará um grande problema ... A melhor maneira de lidar com isso é fazer verificações nulas sempre que necessário durante o processo de desenvolvimento. Isso economizará muito tempo.

Ao encontrar por nome, quero dizer que algumas estruturas permitem que você FIndObjects usando seqüências de caracteres e o código pode ser assim: FindObject ("ObjectName");


Curiosamente, nenhuma das respostas nesta página menciona os dois casos extremos, espero que ninguém se importe se eu adicioná-los:

Edge case # 1: acesso simultâneo a um dicionário

Dicionários genéricos no .NET não são thread-safe e eles às vezes podem lançar um NullReferenceou até mesmo (mais freqüente) um KeyNotFoundExceptionquando você tenta acessar uma chave de dois threads simultâneos. A exceção é bastante enganadora neste caso.

Caso de borda # 2: código não seguro

Se a NullReferenceExceptionfor lançada pelo unsafecódigo, você poderá ver suas variáveis ​​de ponteiro e verificá-las IntPtr.Zeroou algo do tipo. Qual é a mesma coisa ("exceção de ponteiro nulo"), mas no código não seguro, as variáveis ​​são geralmente convertidas em tipos de valor / arrays, etc., e você bate a cabeça contra a parede, imaginando como um tipo de valor pode lançar exceção.

(Outra razão para não usar código não seguro, a menos que você precise, a propósito)


Isso significa que seu código usou uma variável de referência de objeto que foi definida como nula (ou seja, não referencia uma instância de objeto real).

Para evitar o erro, os objetos que poderiam ser nulos devem ser testados para null antes de serem usados.

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
}

NullReferenceException ou referência de objeto não definida para uma instância de um objeto ocorre quando um objeto da classe que você está tentando usar não é instanciado. Por exemplo:

Suponha que você tenha uma classe chamada Student.

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

Agora, considere outra classe em que você está tentando recuperar o nome completo do aluno.

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

Como visto no código acima, a instrução Student s - apenas declara a variável do tipo Student, observe que a classe Student não é instanciada neste momento. Portanto, quando a instrução s.GetFullName () for executada, ela lançará o NullReferenceException.


Se considerarmos cenários comuns nos quais essa exceção pode ser lançada, acessando propriedades com o objeto no topo.

Ex:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

aqui, se o endereço for nulo, você obterá NullReferenceException.

Então, como prática, devemos sempre usar a verificação nula, antes de acessar propriedades em tais objetos (especialmente em genéricos)

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception

Simon Mourier deu este exemplo :

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

onde uma conversão de unboxing (cast) de object (ou de uma das classes System.ValueTypeou System.Enum, ou de um tipo de interface) para um tipo de valor (diferente de Nullable<>) em si, fornece o NullReferenceException.

Na outra direção, uma conversão de boxe de um Nullable<>que tenha HasValueigual false a um tipo de referência, pode dar uma nullreferência que pode levar a um NullReferenceException. O exemplo clássico é:

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

Às vezes o boxe acontece de outra maneira. Por exemplo, com este método de extensão não genérico:

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

o seguinte código será problemático:

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

Esses casos surgem devido às regras especiais que o runtime usa quando instaurações de boxe Nullable<>.


Você pode corrigir NullReferenceException de uma maneira limpa usando Operadores Nulos-condicionais em c # 6 e escrever menos código para manipular verificações nulas.

Ele é usado para testar o valor nulo antes de executar uma operação de acesso de membro (?.) Ou índice (? [).

Exemplo

  var name = p?.Spouse?.FirstName;

é equivalente a:

    if (p != null)
    {
        if (p.Spouse != null)
        {
            name = p.Spouse.FirstName;
        }
    }

O resultado é que o nome será nulo quando p for nulo ou quando p.Spouse for nulo.

Caso contrário, o nome da variável receberá o valor de p.Spouse.FirstName.

Para mais detalhes: Operadores com condições nulas


A NullReferenceExceptioné lançado quando estamos tentando acessar as propriedades de um objeto nulo ou quando um valor de cadeia se torna vazio e estamos tentando acessar os métodos de string.

Por exemplo:

  1. Quando um método de string de uma string vazia é acessado:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
  2. Quando uma propriedade de um objeto nulo é acessada:

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

Eu tenho uma perspectiva diferente para responder isso. Esse tipo de resposta "o que mais posso fazer para evitar isso? "

Ao trabalhar em camadas diferentes , por exemplo, em um aplicativo MVC, um controlador precisa de serviços para chamar operações de negócios. Nesses cenários, o Container de Injeção de Dependência pode ser usado para inicializar os serviços para evitar o NullReferenceException . Isso significa que você não precisa se preocupar com a verificação de null e apenas chamar os serviços do controlador como se eles estivessem sempre disponíveis (e inicializados) como um singleton ou um protótipo.

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

Isso significa que a variável em questão é apontada para nada. Eu poderia gerar isso assim:

SqlConnection connection = null;
connection.Open();

Isso causará o erro porque, embora eu tenha declarado a variável " connection", ela não está apontando para nada. Quando tento chamar o membro " Open", não há nenhuma referência para resolvê-lo e isso causará o erro.

Para evitar esse erro:

  1. Sempre inicialize seus objetos antes de tentar fazer algo com eles.
  2. Se você não tiver certeza se o objeto é nulo, verifique com ele object == null.

A ferramenta Resharper do JetBrains identificará todos os locais em seu código que têm a possibilidade de um erro de referência nulo, permitindo que você coloque uma verificação nula. Este erro é a fonte número um de bugs, IMHO.


Literalmente, a maneira mais fácil de corrigir um NullReferenceExeption é de duas maneiras. Se você tem um GameObject por exemplo com um script anexado e uma variável chamada rb (rigidbody), esta variável irá iniciar null quando você iniciar o seu jogo.
É por isso que você obtém um NullReferenceExeption porque o computador não possui dados armazenados nessa variável.

Eu vou estar usando uma variável RigidBody como um exemplo.
Podemos adicionar dados muito facilmente, na verdade, de algumas maneiras:

  1. Adicione um RigidBody ao seu objeto com AddComponent> Physics> Rigidbody
    Então entre no seu script e digite rb = GetComponent<Rigidbody>();
    Esta linha de código funciona melhor sob o seu Start()ou Awake()funções.
  2. Você pode adicionar um componente programaticamente e atribuir a variável ao mesmo tempo com uma linha de código: rb = AddComponent<RigidBody>();

Notas adicionais: Se você deseja que a unidade adicione um componente ao seu objeto e talvez tenha esquecido de adicionar um, digite [RequireComponent(typeof(RigidBody))]acima da declaração de classe (o espaço abaixo de todos os seus usos).
Aproveite e divirta-se fazendo jogos!


Na questão de "o que devo fazer a respeito" , pode haver muitas respostas.

Uma maneira mais "formal" de impedir tais condições de erro durante o desenvolvimento é aplicar o design por contrato em seu código. Isso significa que você precisa definir invariantes de classe e / ou até mesmo pré - condições de função / método e pós - condições em seu sistema, durante o desenvolvimento.

Em suma, os invariantes de classe garantem que haverá algumas restrições em sua classe que não serão violadas no uso normal (e, portanto, a classe não ficará em um estado inconsistente). Pré-condições significam que os dados dados como entrada para uma função / método devem seguir algumas restrições definidas e nunca violá-las, e pós - condições significam que uma saída de função / método deve seguir as restrições estabelecidas novamente sem nunca violá-las. As condições do contrato nunca devem ser violadas durante a execução de um programa livre de erros, portanto, o projeto por contrato é verificado na prática no modo de depuração, enquanto é desativado em versões, para maximizar o desempenho do sistema desenvolvido.

Dessa forma, você pode evitar NullReferenceExceptioncasos que são resultados da violação das restrições definidas. Por exemplo, se você usar uma propriedade de objeto Xem uma classe e depois tentar chamar um de seus métodos e Xtiver um valor nulo, isso levará a NullReferenceException:

public X { get; set; }

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

Mas se você definir "propriedade X nunca deve ter um valor nulo" como condição prévia do método, será possível evitar o cenário descrito anteriormente:

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

Por essa razão, o projeto Code Contracts existe para aplicativos .NET.

Alternativamente, o design por contrato pode ser aplicado usando assertions .

ATUALIZAÇÃO: Vale a pena mencionar que o termo foi cunhado por Bertrand Meyer em conexão com o seu design da linguagem de programação de Eiffel .


Outro caso geral em que uma pessoa pode receber essa exceção envolve a simulação de classes durante o teste de unidade. Independentemente da estrutura de simulação que está sendo usada, você deve garantir que todos os níveis apropriados da hierarquia de classes sejam apropriadamente ridicularizados. Em particular, todas as propriedades das HttpContextquais são referenciadas pelo código em teste devem ser ridicularizadas.

Consulte " NullReferenceException lançada ao testar o AuthorizationAttribute personalizado " para um exemplo um pouco detalhado.


Outro cenário é quando você lança um objeto nulo em um tipo de valor . Por exemplo, o código abaixo:

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

Vai jogar NullReferenceExceptionno elenco. Parece bastante óbvio no exemplo acima, mas isso pode acontecer em mais cenários complicados de "ligação tardia" em que o objeto nulo foi retornado de algum código que você não possui, e a conversão é, por exemplo, gerada por algum sistema automático.

Um exemplo disso é esse fragmento de ligação simples do ASP.NET com o controle Calendar:

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

Aqui, SelectedDatena verdade , é uma propriedade - do DateTimetipo - do tipo CalendarWeb Control, e a ligação poderia perfeitamente retornar algo nulo. O gerador implícito do ASP.NET criará uma parte do código que será equivalente ao código de conversão acima. E isso vai levantar um NullReferenceExceptionque é bastante difícil de detectar, porque está no código gerado pelo ASP.NET que compila bem ...


Se você não inicializou um tipo de referência e deseja definir ou ler uma de suas propriedades, ele lançará um NullReferenceException .

Exemplo:

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

Você pode simplesmente evitar isso verificando se a variável não é nula:

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

Para entender completamente por que uma NullReferenceException é lançada, é importante saber a diferença entre tipos de valor e tipos de referência .

Portanto, se você está lidando com tipos de valor , o NullReferenceExceptions não pode ocorrer. Embora você precise manter-se alerta ao lidar com tipos de referência !

Apenas tipos de referência, como o nome sugere, podem conter referências ou apontar literalmente para nada (ou 'null'). Considerando que os tipos de valor sempre contêm um valor.

Tipos de referência (estes devem ser verificados):

  • dinâmico
  • objeto
  • corda

Tipos de valor (você pode simplesmente ignorar esses):

  • Tipos numéricos
  • Tipos integrais
  • Tipos de ponto flutuante
  • decimal
  • bool
  • Estruturas definidas pelo usuário

Tipos de referência padrão para null para indicar que eles não estão fazendo referência a qualquer objeto. Portanto, se você tentar acessar o objeto que está sendo referenciado e não houver um, obterá uma NullReferenceException .

Por ex:

SqlConnection connection = null;
connection.Open();

Quando você executar este código, você receberá:

System.NullReferenceException: Object reference not set to an instance of an object.

Você pode evitar esse erro codificando assim:

if (connection != null){
    connection.Open();
}

Nota: Para evitar este erro, você deve sempre inicializar seus objetos antes de tentar fazer algo com eles.





nullreferenceexception