Eu tenho algum código e quando executa, 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?
Eu tenho algum código e quando executa, 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?
Respostas:
Você está tentando usar algo que é null
(ou Nothing
no VB.NET). Isso significa que você deve defini-lo como null
ou nunca defini-lo como qualquer coisa.
Como qualquer outra coisa, null
é repassado. Se estiver null
no método "A", pode ser que o método "B" tenha passado a null
para o método "A".
null
pode ter significados diferentes:
NullReferenceException
.null
intencionalmente para indicar que não há valor significativo disponível. Observe que o C # tem o conceito de tipos de dados nulos para variáveis (como as tabelas do banco de dados podem ter campos nulos) - você pode atribuir null
a eles para indicar que não há valor armazenado nele, por exemplo, int? a = null;
onde o ponto de interrogação indica que é permitido armazenar nulo em variável a
. Você pode verificar isso com if (a.HasValue) {...}
ou com if (a==null) {...}
. Variáveis anuláveis, como a
este exemplo, permitem acessar o valor via a.Value
explicitamente, ou apenas como via normal a
. a.Value
lança um em InvalidOperationException
vez de um NullReferenceException
se a
énull
- você deve fazer a verificação antecipadamente, ou seja, se você tiver outra variável anulável int b;
, deverá fazer atribuições como if (a.HasValue) { b = a.Value; }
ou mais curta if (a != null) { b = a; }
.O restante deste artigo entra em mais detalhes e mostra os erros que muitos programadores cometem, o que pode levar a um NullReferenceException
.
O runtime
jogando um NullReferenceException
sempre significa a mesma coisa: você está tentando usar uma referência, e a referência não é inicializado (ou foi uma vez inicializado, mas é não inicializado).
Isso significa que a referência é null
e você não pode acessar membros (como métodos) por meio de uma null
referência. 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 string
referência apontando para null
.
Como você encontra a fonte de um NullReferenceException
? Além de observar a exceção em si, que será lançada exatamente no local em que ocorre, as regras gerais de depuração no Visual Studio se aplicam: coloque pontos de interrupção estratégicos e inspecione suas variáveis , passando o mouse sobre seus nomes, abrindo um ( Rápido) Observe a janela ou use os vários painéis de depuração, como Locals e Autos.
Se você deseja descobrir onde a referência está ou não está definida, clique com o botão direito do mouse no nome e selecione "Localizar todas as referências". Você pode colocar um ponto de interrupção em todos os locais encontrados e executar seu programa com o depurador conectado. Sempre que o depurador interrompe esse ponto de interrupção, é necessário determinar se você espera que a referência seja nula, inspecione a variável e verifique se ela aponta para uma instância quando você espera.
Seguindo o fluxo do programa dessa maneira, é possível encontrar o local em que a instância não deve ser nula e por que ela não está definida corretamente.
Alguns cenários comuns em que a exceção pode ser lançada:
ref1.ref2.ref3.member
Se ref1 ou ref2 ou ref3 for nulo, você receberá a NullReferenceException
. Se você deseja resolver o problema, descubra qual deles é 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
, HttpContext.Current
poderia ser nulo ou a User
propriedade poderia ser nula ou a Identity
propriedade poderia ser nula.
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ê deseja evitar a referência nula filho (Pessoa), você pode inicializá-la no construtor do objeto pai (Livro).
O mesmo se aplica aos inicializadores de objetos 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 de Book
, mas não uma nova instância Person
, portanto Author
a propriedade permanece imóvel null
.
public class Person
{
public ICollection<Book> Books { get; set; }
}
public class Book
{
public string Title { get; set; }
}
A coleção aninhada Initializers
se comporta 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" });
O new Person
único cria uma instância de Person
, mas a Books
coleção ainda é null
. A Initializer
sintaxe da coleção não cria uma coleção para p1.Books
, ela se traduz apenas nas p1.Books.Add(...)
instruções.
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
// initialized. There is no Person to set the Age for.
long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
// Use array[0] = new long[2]; first.
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
public class Person
{
public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
// on the line above. "p" is null because the
// first element we added to the list is null.
public class Demo
{
public event EventHandler StateChanged;
protected virtual void OnStateChanged(EventArgs e)
{
StateChanged(this, e); // Exception is thrown here
// if no event handlers have been attached
// to StateChanged event
}
}
###Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
classe pública 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 de prefixar campos com um sublinhado:
private Customer _customer;
public partial class Issues_Edit : System.Web.UI.Page
{
protected TestIssue myIssue;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Only called on first load, not when button clicked
myIssue = new TestIssue();
}
}
protected void SaveButton_Click(object sender, EventArgs e)
{
myIssue.Entry = "NullReferenceException here!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
Se a exceção ocorrer ao fazer referência a uma propriedade de @Model
em um ASP.NET MVC View
, você precisará entender que isso Model
é definido no seu método de ação, quando você return
visualiza. Quando você retorna um modelo vazio (ou propriedade de modelo) do 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 -->
WPF
Os controles são criados durante a chamada InitializeComponent
na ordem em que aparecem na árvore visual. A NullReferenceException
será gerado no caso de controles criados anteriormente com manipuladores de eventos etc., aquele disparo durante o InitializeComponent
qual os controles criados tardiamente serão referenciados.
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 label1
. Se comboBox1_SelectionChanged
tentar referenciar `label1, ele ainda não foi criado.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Alterar a ordem das declarações em XAML
(ou seja, listar label1
antes comboBox1
, ignorando questões da filosofia do design, pelo menos resolveria o problema NullReferenceException
aqui).
as
var myThing = someObject as Thing;
Isso não InvalidCastException
gera um, mas retorna a null
quando o elenco falha (e quando someObject
é nulo). Então, fique ciente disso.
FirstOrDefault()
eSingleOrDefault()
As versões simples First()
e Single()
lançam exceções quando não há nada. As versões "OrDefault" retornam nulo nesse caso. Então, fique ciente disso.
foreach
lança quando você tenta iterar a coleção nula. Geralmente causado por null
resultado 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çada se os nós não forem encontrados, mas a depuração inicial mostrar que todas as propriedades são válidas:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
e ignore valores nulos.Se, às vezes, você espera que a referência seja nula, verifique null
antes de acessar os membros da instância:
void PrintName(Person p)
{
if (p != null)
{
Console.WriteLine(p.Name);
}
}
null
e forneça um valor padrão.Chamada de métodos que você espera que uma instância possa retornar null
, por exemplo, quando o objeto que está sendo procurado não puder ser encontrado. Você pode optar por retornar um valor padrão quando este for o caso:
string GetCategory(Book b)
{
if (b == null)
return "Unknown";
return b.Category;
}
null
chamadas de método e crie uma exceção personalizada.Você também pode lançar uma exceção personalizada, apenas para capturá-la 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;
}
Debug.Assert
se um valor nunca deve ser null
, para capturar o problema mais cedo do que a exceção ocorre.Quando você sabe durante o desenvolvimento que um método pode, mas nunca deve retornar null
, você pode usar Debug.Assert()
para interromper 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 termine na construção da versão , fazendo com que seja lançadaNullReferenceException
novamente quando estiver book == null
em tempo de execução no modo de liberação.
GetValueOrDefault()
para nullable
tipos de valor para fornecer um valor padrão quando estiverem null
.DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.
appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default
??
[C #] ou If()
[VB].A abreviação para fornecer um valor padrão quando a 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;
}
?.
ou ?[x]
para matrizes (disponíveis em C # 6 e VB.NET 14):Às vezes, isso também é chamado de operador de navegação segura ou Elvis (após seu formato). Se a expressão no lado esquerdo do operador for nula, o lado direito não será avaliado e o nulo será retornado. Isso significa casos como este:
var title = person.Title.ToUpper();
Se a pessoa não tiver um título, isso gerará uma exceção porque está tentando chamar ToUpper
uma propriedade com um valor nulo.
Dentro C# 5
e abaixo, isso pode ser protegido com:
var title = person.Title == null ? null : person.Title.ToUpper();
Agora, a variável title será nula em vez de lançar uma exceção. O C # 6 apresenta uma sintaxe mais curta para isso:
var title = person.Title?.ToUpper();
Isso resultará na variável title null
, e a chamada para ToUpper
não será feita, se person.Title
for null
.
Obviamente, você ainda precisa verificar se title
há nulo ou usar o operador de condição nula junto com o operador de coalescência nula ( ??
) 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 da ?[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á nulo e você poderá verificá-la com segurança. Se ele contiver uma matriz, fará o mesmo que:
elem = myIntArray[i];
e retorna o i<sup>th</sup>
elemento.
Introduzido nos C# 8
contextos nulos e nos tipos de referência anuláveis, executam análises estáticas nas variáveis e fornecem um aviso do compilador se um valor puder ser potencialmente nulo ou tiver sido definido como nulo. Os tipos de referência anuláveis permitem explicitamente que os tipos sejam nulos.
O contexto de anotação anulável e o contexto de aviso anulável podem ser definidos para um projeto usando o Nullable
elemento no seu csproj
arquivo. Este elemento configura como o compilador interpreta a nulidade dos tipos e quais avisos são gerados. As configurações válidas são:
Um tipo de referência anulável é observado usando a mesma sintaxe que os tipos de valor anulável: a ?
é anexado ao tipo da variável.
C#
suporta "blocos iteradores" (chamados "geradores" em outros idiomas populares). Exceções de dereferência nula podem ser particularmente difíceis de depurar em blocos de iteradores 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 whatever
os resultados em null
seguida, MakeFrob
vai jogar. Agora, você pode pensar que a coisa certa a fazer é:
// 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? Como o bloco iterador não é executado até o foreach
! A chamada para GetFrobs
simplesmente retorna um objeto que, quando iterado , executará o bloco iterador.
Ao escrever uma verificação nula como essa, você evita a desreferência nula, mas move a exceção de 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 de 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
é chamada, a verificação nula acontece imediatamente e é GetFrobsForReal
executada quando a sequência é iterada.
Se você examinar a fonte de referência para LINQ
Objetos, verá que essa técnica é usada por toda parte. É um pouco mais complicado de escrever, mas facilita muito a depuração de erros de nulidade. Otimize seu código para a conveniência do chamador, não para o autor .
C#
possui 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ódigo inseguro, a menos que tenha um entendimento profundo e profundo de como a memória funciona .
No modo não seguro, você deve estar ciente de dois fatos importantes:
Para entender por que isso acontece, é útil entender como o .NET produz exceções de desreferência nula em primeiro lugar. (Esses detalhes se aplicam ao .NET em execução no Windows; outros sistemas operacionais usam mecanismos semelhantes.)
A memória é virtualizada 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 da memória possui sinalizadores definidos que determinam como ela pode ser usada: leitura, gravação, execução etc. A página mais baixa é marcada como "produza um erro, se alguma vez for usada de alguma maneira".
Um ponteiro nulo e uma referência nula 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 detecta esse erro e o transforma na exceção de desreferência nula.
É por isso que desreferenciar um ponteiro nulo e uma referência nula produz a mesma exceção.
E o segundo ponto? Anular a referência a 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 duas entradas e um ponteiro não gerenciado igual a nulo. Se tentarmos desreferenciar o segundo int na estrutura, CLR
ele não tentará acessar o armazenamento no local zero; ele acessará o armazenamento no local quatro. Mas, logicamente, essa é uma dereferência nula, porque estamos chegando a esse endereço via nula.
Se você estiver trabalhando com código não seguro e receber uma exceção de desreferência nula, lembre-se de que o ponteiro incorreto não precisa ser nulo. Pode ser qualquer local na página mais baixa e essa exceção será produzida.
new Book { Author = { Age = 45 } };
Como é que a inicialização interna ainda ... Não consigo pensar em uma situação em que o init interno funcionaria, mas compila e o intellisense funciona ... A menos que por estruturas?
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).
Esta resposta usará termos, sintaxe e contexto do Visual Basic. Os exemplos usados vêm de um grande número de perguntas anteriores do Stack Overflow. Isso é para maximizar a relevância usando os tipos de situações geralmente vistas nas postagens. Um pouco mais de explicação também é fornecida para aqueles que precisam. Um exemplo semelhante ao seu é muito provável aqui.
Nota:
NullReferenceException
(NRE), como encontrá-lo, como corrigi-lo e como evitá-lo. Um NRE pode ser causado de várias maneiras, por isso é improvável que seja seu único encontro.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:
Como o problema é uma referência a objeto Nothing
, a resposta é examiná-lo para descobrir qual. Em seguida, determine por que não foi 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 todos os blocos Try / Catch do código relevante, especialmente aqueles onde não há nada no bloco Catch. Isso fará com que seu código falhe ao tentar usar um objeto que é Nothing
. É isso que você deseja, porque identificará o local exato do problema e permitirá identificar o objeto que está causando o problema.
A MsgBox
na captura que exibe Error while...
será de pouca ajuda. Esse método também leva a questões muito ruins de Stack Overflow, porque você não pode descrever a exceção real, o objeto envolvido ou mesmo a linha de código onde ela ocorre.
Você também pode usar o Locals Window
( Debug -> Windows -> Locals ) para examinar seus objetos.
Depois de saber qual e onde está o problema, geralmente é bastante fácil de corrigir e mais rápido do que postar uma nova pergunta.
Veja também:
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
O problema é que Dim
não cria um objeto CashRegister ; apenas declara uma variável denominada reg
desse tipo. Declarar uma variável de objeto e criar uma instância são duas coisas diferentes.
Remédio
O New
operador geralmente 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 apenas criar a instância posteriormente:
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
Isso criará uma variável localreg
, que existe apenas nesse contexto (sub). A reg
variável com o nível do módulo Scope
que você usará em qualquer outro lugar permanece Nothing
.
A falta do
New
operador é a principal causa de problemasNullReference Exceptions
nas perguntas de estouro de pilha revisadas.O Visual Basic tenta tornar o processo claro repetidamente usando
New
: Usar oNew
Operador cria um novo objeto e chamaSub New
- o construtor - onde seu objeto pode executar qualquer outra inicialização.
Para ser claro, Dim
(ou Private
) declara apenas uma variável e sua Type
. O escopo da variável - se existe para todo o módulo / classe ou é local para um procedimento - é determinado pelo local em que é declarado. Private | Friend | Public
define o nível de acesso, não o escopo .
Para mais informações, veja:
As matrizes também devem ser instanciadas:
Private arr as String()
Essa matriz foi declarada apenas, não criada. 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 uma matriz 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 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: Matriz 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 Foo
objetos nela não.
Remédio
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Usar um List(Of T)
tornará bastante 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:
As coleções do .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)
Uma supervisão comum é uma classe que usa uma coleção Type
:
Public Class Foo
Private barList As List(Of Bar)
Friend Function BarCount As Integer
Return barList.Count
End Function
Friend Sub AddItem(newBar As Bar)
If barList.Contains(newBar) = False Then
barList.Add(newBar)
End If
End Function
Qualquer procedimento resultará em um NRE, porque barList
é declarado apenas, não instanciado. Criar uma instância de Foo
também não criará uma instância do interno barList
. 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 List(Of T)
Classe .
Trabalhando com bancos de dados apresenta muitas oportunidades para um NullReference porque pode haver muitos objetos ( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) em uso ao mesmo tempo. 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 ds
objeto Conjunto de dados foi declarado, mas uma instância nunca foi criada. O DataAdapter
irá preencher um existente DataSet
, não criar um. Nesse caso, como ds
é uma variável local, o IDE avisa que isso pode acontecer:
Quando declarado como uma variável de nível de módulo / classe, como parece ser o caso con
, o compilador não pode saber se o objeto foi criado por um procedimento upstream. Não ignore 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
vs Employee
. Não havia um DataTable
nome "Funcionário" criado; portanto, um NullReferenceException
resultado está tentando acessá-lo. Outro problema em potencial é supor que haverá o Items
que pode não ser assim quando o SQL incluir uma cláusula WHERE.
Remédio
Como isso usa uma tabela, a utilização Tables(0)
evitará erros de ortografia. O exame 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 retornando o número de Rows
afetados que também pode ser testado:
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
Ele DataAdapter
será fornecido TableNames
como mostrado no exemplo anterior, mas não analisa nomes da tabela SQL ou do banco de dados. Como resultado, faz ds.Tables("TICKET_RESERVATION")
referência a uma tabela inexistente.
O remédio é o mesmo, faça referência à tabela por índice:
If ds.Tables(0).Rows.Count > 0 Then
Veja também DataTable Class .
If myFoo.Bar.Items IsNot Nothing Then
...
O código está testando apenas Items
enquanto ambos myFoo
e Bar
também pode ser Nothing. O remédio é testar toda a cadeia ou caminho dos 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 subsequentes não serão executados quando a primeira False
condição for encontrada. Isso permite que o código 'perfure' com segurança no (s) objeto (s), um 'nível' de cada vez, avaliando myFoo.Bar
somente depois que (e se) myFoo
for determinado como válido. Cadeias ou caminhos de objetos podem ficar muito longos ao codificar objetos complexos:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
Não é possível fazer referência a nada 'downstream' de um null
objeto. Isso também se aplica aos controles:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Aqui, myWebBrowser
ou Document
poderia ser Nothing ou o formfld1
elemento pode não existir.
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 possa não ter selecionado algo em um ou mais controles da interface do usuário. ListBox1.SelectedItem
pode muito bem ser Nothing
, então ListBox1.SelectedItem.ToString
resultará em um NRE.
Remédio
Valide os dados antes de usá-los (também use Option Strict
e parâ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
Como alternativa, você pode usar (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Public Class Form1
Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
Controls("TextBox2"), Controls("TextBox3"), _
Controls("TextBox4"), Controls("TextBox5"), _
Controls("TextBox6")}
' same thing in a different format:
Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}
' Immediate NRE:
Private somevar As String = Me.Controls("TextBox1").Text
Essa é uma maneira bastante comum de obter um NRE. Em C #, dependendo de como é codificado, o IDE relatará que Controls
não existe no contexto atual ou "não pode fazer referência a membro não estático". Então, até certo ponto, essa é uma situação apenas de VB. Também é complexo porque pode resultar em uma cascata de falha.
As matrizes e coleções não podem ser inicializadas dessa maneira. Esse código de inicialização será executado antes que o construtor crie o Form
ou o Controls
. Como um resultado:
somevar
atribuição resultará em uma NRE imediata porque Nothing não possui uma .Text
propriedadeA referência a elementos da matriz posteriormente resultará em um NRE. Se você fizer isso Form_Load
, devido a um erro estranho, o IDE poderá não relatar a exceção quando isso acontecer. A exceção será exibida mais tarde quando seu código tentar usar a matriz. Essa "exceção silenciosa" é detalhada nesta postagem . Para nossos propósitos, a chave é que, quando algo catastrófico acontece ao criar um formulário ( Sub New
ou Form Load
evento), as exceções podem não ser relatadas, o código sai do procedimento e apenas exibe o formulário.
Como nenhum outro código no seu evento Sub New
ou Form Load
será executado após o NRE, muitas outras coisas podem ser deixadas não inicializadas.
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 toda e qualquer referência de controle e componente, 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 fazer existir. Isso pode ser feito Sub New
desde que seu código seja após a InitializeComponent
chamada:
' 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 do array ainda pode não estar fora de perigo. Quaisquer controles que estejam em um controle de contêiner (como um GroupBox
ou Panel
) não serão encontrados Me.Controls
; eles estarão na coleção Controls desse Panel ou GroupBox. Um controle também não será retornado quando o nome do controle estiver incorreto ( "TeStBox2"
). Nesses casos, Nothing
será novamente armazenado nesses elementos da matriz e um NRE resultará quando você tentar fazer referência a ele.
Isso deve ser fácil 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 Controls
coleçã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...})
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
É um caso em que o IDE avisa que ' nem todos os caminhos retornam um valor e NullReferenceException
podem resultar '. Você pode suprimir o aviso, substituindo Exit Function
por Return Nothing
, mas isso não resolve o problema. Qualquer coisa que tentar usar o retorno quando someCondition = False
resultará em um NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Remédio
Substitua Exit Function
na função por Return bList
. Retornar um vazio List
não é o mesmo que retornar Nothing
. Se houver uma chance de um objeto retornado Nothing
, teste antes de usá-lo:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Um Try / Catch mal implementado pode ocultar 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 é o caso de um objeto que não está sendo criado conforme o esperado, mas também demonstra a contra-utilidade de um vazio Catch
.
Há uma vírgula extra no SQL (após 'endereço de email') que resulta em uma exceção em .ExecuteReader
. Após o Catch
não fazer nada, Finally
tenta executar a limpeza, mas como você não pode Close
um DataReader
objeto nulo , NullReferenceException
resulta em um novo resultado.
Um Catch
bloco vazio é o playground do diabo. Este OP ficou confuso por que ele estava recebendo um NRE no Finally
bloco. Em outras situações, um vazio Catch
pode resultar em algo muito mais a jusante e fazer com que você gaste tempo olhando 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. Os blocos Try / Catch não têm como objetivo ocultar exceções da pessoa qualificada exclusivamente para corrigi-los - o desenvolvedor.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
A IsDBNull
funçã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 o Nothing e, em seguida, obter 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
...
FirstOrDefault
retorna o primeiro item ou o valor padrão, que é Nothing
para tipos de referência e nunca DBNull
:
If getFoo IsNot Nothing Then...
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
Se um CheckBox
com chkName
não puder ser encontrado (ou existir em a GroupBox
), chk
será Nothing e tentar fazer referência a qualquer propriedade resultará em uma exceção.
Remédio
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
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 dgvBooks
tiver AutoGenerateColumns = True
, ele criará as colunas, mas não as nomeará; portanto, o código acima falhará quando as referenciar por nome.
Remédio
Nomeie as colunas manualmente ou faça referência por índice:
dgvBooks.Columns(0).Visible = True
xlWorkSheet = xlWorkBook.Sheets("sheet1")
For i = 0 To myDGV.RowCount - 1
For j = 0 To myDGV.ColumnCount - 1
For k As Integer = 1 To myDGV.Columns.Count
xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
Next
Next
Next
Quando você DataGridView
tiver AllowUserToAddRows
como True
(o padrão), o campo Cells
em branco / nova linha 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/Each
loop e teste a IsNewRow
propriedade para determinar se é a última linha. Isso funciona se AllowUserToAddRows
é verdadeiro 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 n
loop, modifique a contagem de linhas ou use Exit For
quando IsNewRow
for verdadeiro.
Sob certas circunstâncias, tentar usar um item do My.Settings
qual é um StringCollection
pode resultar em um NullReference na primeira vez que você o usa. 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ê tiver adicionado anteriormente uma entrada inicial à coleção (no editor de Configurações). Como a coleção é (aparentemente) inicializada quando um item é adicionado, ela permanece Nothing
quando não há itens no editor de Configurações a serem adicionados.
Remédio
Inicialize a coleção de configurações no Load
manipulador 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 Settings
coleção só precisa ser inicializada na primeira vez que o aplicativo é 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.
Você provavelmente esqueceu o New
operador.
ou
Algo que você assumiu que executaria perfeitamente para retornar um objeto inicializado ao seu código, não o fez.
Não ignore os avisos do compilador (sempre) e use Option Strict On
(sempre).
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;
Ele jogará um NullReferenceException
no elenco. Parece bastante óbvio no exemplo acima, mas isso pode acontecer em cenários intrincados 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 é este fragmento de ligação simples do ASP.NET com o controle Calendar:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Aqui, de SelectedDate
fato , é uma propriedade - do DateTime
tipo - do tipo Calendar
Web Control, e a ligação pode retornar perfeitamente algo nulo. O gerador implícito do ASP.NET criará um código que será equivalente ao código de conversão acima. E isso irá gerar um NullReferenceException
que é bastante difícil de detectar, porque está no código gerado pelo ASP.NET que compila bem ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Isso significa que a variável em questão não está apontada para nada. Eu poderia gerar isso assim:
SqlConnection connection = null;
connection.Open();
Isso lançará o erro porque, embora eu tenha declarado a variável " connection
", ela não está apontada para nada. Quando tento ligar para o membro " Open
", não há referência para sua resolução e isso gerará o erro.
Para evitar esse erro:
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ê faça uma verificação nula. Este erro é a fonte número um de bugs, IMHO.
Isso significa que seu código usou uma variável de referência de objeto que foi definida como nula (ou seja, não fez referência a uma instância de objeto real).
Para evitar o erro, os objetos que poderiam ser nulos devem ser testados quanto a nulos antes de serem utilizados.
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
}
Esteja ciente de que, independentemente do cenário, a causa é sempre a mesma no .NET:
Você está tentando usar uma variável de referência cujo valor é
Nothing
/null
. Quando o valor éNothing
/null
para a variável de referência, isso significa que na verdade não está mantendo uma referência a uma instância de qualquer objeto que exista na pilha.Você nunca atribuiu algo à variável, nunca criou uma instância do valor atribuído à variável, ou configurou a variável igual a
Nothing
/null
manualmente ou chamou uma função que definiu a variável paraNothing
/null
para você.
Um exemplo dessa exceção sendo lançada é: Quando você está tentando verificar algo, isso é nulo.
Por exemplo:
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
O tempo de execução do .NET lançará uma NullReferenceException quando você tentar executar uma ação em algo que não foi instanciado, ou seja, o código acima.
Em comparação com um ArgumentNullException que normalmente é lançado como uma medida defensiva se um método espera que o que está sendo passado para ele não seja nulo.
Mais informações estão em C # NullReferenceException e Null Parameter .
Atualização C # 8.0, 2019: tipos de referência anuláveis
O C # 8.0 apresenta tipos de referência nulos e tipos de referência não nulos . Portanto, apenas tipos de referência anuláveis devem ser verificados para evitar uma NullReferenceException .
Se você não inicializou um tipo de referência e deseja definir ou ler uma de suas propriedades, ele lançará uma 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] [3].
Portanto, se você estiver lidando com tipos de valor , NullReferenceExceptions não poderá ocorrer. Embora você precise manter-se alerta ao lidar com tipos de referência !
Somente tipos de referência, como o nome está sugerindo, podem conter referências ou apontar literalmente para nada (ou 'nulo'). Enquanto os tipos de valor sempre contêm um valor.
Tipos de referência (estes devem ser verificados):
Tipos de valor (você pode simplesmente ignorar estes):
Outro caso em NullReferenceExceptions
que isso pode acontecer é o uso (incorreto) do as
operador :
class Book {
public string Name { get; set; }
}
class Car { }
Car mycar = new Car();
Book mybook = mycar as Book; // Incompatible conversion --> mybook = null
Console.WriteLine(mybook.Name); // NullReferenceException
Aqui Book
e Car
são tipos incompatíveis; a Car
não pode ser convertido / convertido em a Book
. Quando esse elenco falha, as
retorna null
. O uso mybook
após isso causa a NullReferenceException
.
Em geral, você deve usar um elenco ou as
, da seguinte maneira:
Se você espera que a conversão de tipo seja sempre bem-sucedida (ou seja, você sabe o que o objeto deve estar adiantado), use uma conversão:
ComicBook cb = (ComicBook)specificBook;
Se você não tiver certeza do tipo, mas deseja tentar usá-lo como um tipo específico, use as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Você está usando o objeto que contém a referência de valor nulo. Portanto, está dando uma exceção nula. No exemplo, o valor da sequência é nulo e, ao verificar seu comprimento, ocorreu a exceção.
Exemplo:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
O erro de exceção é:
Exceção não tratada:
System.NullReferenceException: referência de objeto não definida para uma instância de um objeto. em Program.Main ()
Enquanto o que causa um NullReferenceExceptions e abordagens para evitar / corrigir essa exceção foi abordado em outras respostas, o que muitos programadores ainda não aprenderam é como depurar independentemente essas exceções durante o desenvolvimento.
No Visual Studio, isso geralmente é fácil, graças ao Visual Studio Debugger .
Primeiro, verifique se o erro correto será capturado - consulte Como permito quebras em 'System.NullReferenceException' no VS2010? Nota 1
Em seguida, inicie com Depuração (F5) ou Anexe [o VS Debugger] ao processo em execução . Ocasionalmente, pode ser útil usá-lo Debugger.Break
, o que solicitará o lançamento do depurador.
Agora, quando a NullReferenceException for lançada (ou não tratada), o depurador irá parar (lembra-se da regra definida acima?) Na linha em que ocorreu a exceção. Às vezes, o erro será fácil de detectar.
Por exemplo, na linha a seguir, o único código que pode causar a exceção é se o valor for myString
avaliado como nulo. Isso pode ser verificado olhando para a Janela de inspeção ou executando expressões na Janela imediata .
var x = myString.Trim();
Em casos mais avançados, como o seguinte, você precisará usar uma das técnicas acima (Monitorar ou Windows Imediato) para inspecionar as expressões e determinar se str1
foi nulo ou se str2
foi nulo.
var x = str1.Trim() + str2.Trim();
Depois que a exceção é lançada, geralmente é trivial raciocinar para trás para descobrir onde o valor nulo foi [incorretamente] introduzido -
Aproveite o tempo necessário para entender a causa da exceção. Inspecione expressões nulas. Inspecione as expressões anteriores que poderiam ter resultado em tais expressões nulas. Adicione pontos de interrupção e siga o programa conforme apropriado. Use o depurador.
1 Se a interrupção na execução for muito agressiva e o depurador parar em um NPE na biblioteca .NET ou de terceiros, a interrupção na não tratada pelo usuário poderá ser usada para limitar as exceções capturadas. Além disso, o VS2012 apresenta Just My Code, que eu recomendo ativar também.
Se você estiver depurando com o Just My Code ativado, o comportamento será um pouco diferente. Com o Just My Code ativado, o depurador ignora as exceções do CLR (Common Language Runtime) de primeira chance que são lançadas fora do My Code e não passam pelo My Code
Simon Mourier deu este exemplo :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
onde uma conversão de unboxing (conversão) de object
(ou de uma das classes System.ValueType
ou System.Enum
, ou de um tipo de interface) para um tipo de valor (diferente de Nullable<>
) em si fornece NullReferenceException
.
Na outra direção, uma conversão de boxe de um Nullable<>
que é HasValue
igual false
a um tipo de referência pode fornecer uma null
referência que pode posteriormente levar a a 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 código a seguir 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 tempo de execução usa ao encaixar as Nullable<>
instâncias.
Adicionando um caso em que o nome da classe da entidade usada na estrutura da entidade é o mesmo da classe de um arquivo code-behind do formulário da web.
Suponha que você tenha um formulário da Web Contact.aspx cuja classe por trás do código seja Contato e você tenha um nome de entidade Contato.
O código a seguir lançará uma NullReferenceException quando você chamar context.SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Por uma questão de completude da classe DataContext
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
e Classe de entidade de contato. Às vezes, as classes de entidade são classes parciais, para que você também possa estendê-las em outros arquivos.
public partial class Contact
{
public string Name {get; set;}
}
O erro ocorre quando a entidade e a classe code-behind estão no mesmo espaço para nome. Para corrigir isso, renomeie a classe da entidade ou a classe code-behind para Contact.aspx.
Razão Ainda não tenho certeza sobre o motivo. Mas sempre que qualquer classe de entidade estender o System.Web.UI.Page, esse erro ocorre.
Para discussão, dê uma olhada em NullReferenceException em DbContext.saveChanges ()
Outro caso geral em que alguém pode receber essa exceção envolve zombar de classes durante o teste de unidade. Independentemente da estrutura de simulação usada, você deve garantir que todos os níveis apropriados da hierarquia de classes sejam simulados corretamente. Em particular, todas as propriedades HttpContext
mencionadas pelo código em teste devem ser ridicularizadas.
Consulte " NullReferenceException lançada ao testar o AuthorizationAttribute personalizado " para obter um exemplo um pouco detalhado.
Eu tenho uma perspectiva diferente para responder a isso. Esse tipo de resposta "o que mais posso fazer para evitá-lo? "
Ao trabalhar em diferentes camadas , por exemplo, em um aplicativo MVC, um controlador precisa de serviços para chamar operações de negócios. Nesses cenários, o Contêiner de injeção de dependência pode ser usado para inicializar os serviços para evitar a NullReferenceException . Isso significa que você não precisa se preocupar em procurar nulos e apenas chamar os serviços do controlador, como se eles sempre estivessem 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();
}
}
Sobre o assunto "o que devo fazer sobre isso" , pode haver muitas respostas.
Uma maneira mais "formal" de impedir essas condições de erro durante o desenvolvimento é aplicar o design por contrato no seu código. Isso significa que você precisa definir invariantes de classe e / ou até pré - condições e pós - condições de função / método em seu sistema durante o desenvolvimento.
Em resumo, 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 entrará em um estado inconsistente). As pré-condições significam que os dados fornecidos como entrada para uma função / método devem seguir algumas restrições definidas e nunca violá-las, e as pós - condições significam que uma saída da função / método deve seguir as restrições definidas 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 design por contrato é verificado na prática no modo de depuração, enquanto está desabilitado nas versões , para maximizar o desempenho do sistema desenvolvido.
Dessa forma, você pode evitar NullReferenceException
casos resultantes da violação das restrições definidas. Por exemplo, se você usar uma propriedade de objeto X
em uma classe e depois tentar chamar um de seus métodos e X
tiver 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 "a propriedade X nunca deve ter um valor nulo" como condição prévia do método, poderá impedir o cenário descrito anteriormente:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Por essa causa, o projeto Code Contracts existe para aplicativos .NET.
Como alternativa, o design por contrato pode ser aplicado usando asserções .
ATUALIZAÇÃO: Vale ressaltar que o termo foi cunhado por Bertrand Meyer em conexão com o design da linguagem de programação Eiffel .
A NullReferenceException
é lançada quando estamos tentando acessar as propriedades de um objeto nulo ou quando um valor de string fica vazio e estamos tentando acessar métodos de string.
Por exemplo:
Quando um método de string de uma string vazia é acessado:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Quando uma propriedade de um objeto nulo é acessada:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
não lançará uma exceção de referência nula. Representa uma string real, embora uma vazia (ie ""
). Como isso tem um objeto para chamar ToLower()
, não faria sentido lançar uma exceção de referência nula lá.
TL; DR: tente usar em Html.Partial
vez deRenderpage
Eu estava começando Object reference not set to an instance of an object
quando tentei renderizar uma View dentro de uma View enviando um Model, assim:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
A depuração mostrou que o modelo era Nulo no MyOtherView. Até que eu mudei para:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
E funcionou.
Além disso, o motivo pelo qual não precisei Html.Partial
começar foi porque o Visual Studio às vezes lança linhas onduladas com aparência de erro embaixo Html.Partial
se estiver dentro de um foreach
loop de construção 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 consegui executar o aplicativo sem problemas com esse "erro". Consegui me livrar do erro alterando a estrutura do foreach
loop para ficar assim:
@foreach(var M in MyEntities){
...
}
Embora eu tenha a sensação de que foi porque o Visual Studio estava interpretando mal os e comercial e os colchetes.
Html.Partial
, não@Html.Partial
Null
), então eu sabia que o erro estava em como eu estava enviando o modelo.
O que você pode fazer sobre isso?
Há muitas boas respostas aqui explicando o que é uma referência nula e como depurá-la. Mas há muito pouco sobre como evitar o problema ou, pelo menos, facilitar a captura.
Verificar argumentos
Por exemplo, os métodos podem verificar os diferentes argumentos para ver se são nulos e lançar ArgumentNullException
uma exceção obviamente criada para esse propósito exato.
O construtor para o ArgumentNullException
even leva o nome do parâmetro e uma mensagem como argumentos para que você possa dizer ao desenvolvedor exatamente qual é o problema.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Use ferramentas
Existem também várias bibliotecas que podem ajudar. "Resharper", por exemplo, pode fornecer avisos enquanto você escreve um código, especialmente se você usar o atributo: NotNullAttribute
Existem "Contratos de código da Microsoft", nos quais você usa sintaxe como a Contract.Requires(obj != null)
que fornece verificação de tempo de execução e compilação: Introdução aos contratos de código .
Há também "PostSharp", que permitirá que você use apenas atributos como este:
public void DoSometing([NotNull] obj)
Ao fazer isso e fazer do PostSharp parte do seu processo de compilação, obj
será verificado se há nulo no tempo de execução. Consulte: Verificação nula PostSharp
Solução de código simples
Ou você pode sempre codificar sua própria abordagem usando código antigo simples. Por exemplo, aqui está uma estrutura que você pode usar para capturar referências nulas. Foi modelado com o mesmo conceito de Nullable<T>
:
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
Você usaria muito semelhante da mesma maneira que usaria Nullable<T>
, exceto com o objetivo de realizar exatamente o oposto - para não permitir null
. aqui estão alguns exemplos:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
é convertido implicitamente para e T
para que você possa usá-lo em qualquer lugar que precisar. Por exemplo, você pode passar um Person
objeto para um método que leva umNotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Como você pode ver acima, como no caso anulável, você acessaria o valor subjacente por meio da Value
propriedade Como alternativa, você pode usar uma conversão explícita ou implícita; pode ver um exemplo com o valor de retorno abaixo:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Ou você pode até usá-lo quando o método retornar T
(nesse caso Person
) fazendo uma conversão. Por exemplo, o código a seguir gostaria apenas do código acima:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combinar com extensão
Combine NotNull<T>
com um método de extensão e você pode cobrir ainda mais situações. Aqui está um exemplo de como o método de extensão pode ser:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
E aqui está um exemplo de como ele pode ser usado:
var person = GetPerson().NotNull();
GitHub
Para sua referência, disponibilizei o código acima no GitHub, você pode encontrá-lo em:
https://github.com/luisperezphd/NotNull
Recurso de idioma relacionado
O C # 6.0 introduziu o "operador condicional nulo" que ajuda um pouco com isso. Com esse recurso, você pode fazer referência a objetos aninhados e, se algum deles for, null
toda a expressão retornaránull
.
Isso reduz o número de verificações nulas que você precisa fazer em alguns casos. A sintaxe é colocar um ponto de interrogação antes de cada ponto. Pegue o seguinte código, por exemplo:
var address = country?.State?.County?.City;
Imagine que esse country
é um objeto do tipo Country
que possui uma propriedade chamada State
e assim por diante. Se country
, State
, County
, ou City
é null
então address will be
nulo . Therefore you only have to check whether
endereço is
null`.
É um ótimo recurso, mas fornece menos informações. Não torna óbvio qual dos quatro é nulo.
Incorporado como Anulável?
C # tem uma abreviação legal para Nullable<T>
, você pode criar algo anulável colocando um ponto de interrogação após o tipoint?
.
Seria bom se C # tinha algo parecido com a NotNull<T>
estrutura acima e teve um atalho semelhante, talvez o ponto de exclamação para que você poderia escrever algo como (!): public void WriteName(Person! person)
.
Curiosamente, nenhuma das respostas nesta página menciona os dois casos extremos, espero que ninguém se importe se eu os adicionar:
Dicionários genéricos no .NET não são seguros para threads e, às vezes, podem gerar um NullReference
ou até (mais frequente) umKeyNotFoundException
quando você tenta acessar uma chave de dois threads simultâneos. A exceção é bastante enganosa neste caso.
Se a NullReferenceException
é lançada pelo unsafe
código, você pode examinar suas variáveis de ponteiro e verificar se háIntPtr.Zero
ou algo assim. O que é a mesma coisa ("exceção de ponteiro nulo"), mas em código inseguro, as variáveis são frequentemente convertidas em tipos / matrizes de valor, etc., e você bate a cabeça na parede, imaginando como um tipo de valor pode gerar isso. exceção.
(Outro motivo para não usar código inseguro, a menos que você precise, a propósito)
null
que maneira?
Você pode corrigir NullReferenceException de maneira limpa usando Operadores com condição nula no c # 6 e escrever menos código para manipular verificações nulas.
É usado para testar nulos 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 obter mais detalhes: Operadores nulos-condicionais
A linha de erro "Referência de objeto não definida para uma instância de um objeto." Afirma que você não atribuiu um objeto de instância a uma referência de objeto e ainda assim está acessando as propriedades / métodos desse objeto.
por exemplo: digamos que você tenha uma classe chamada myClass e ela 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 à referência dessa classe.
Para corrigir isso, é necessário instanciar (atribuir objeto à referência dessa classe).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
A referência NullReferenceException ou Object 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 Aluno.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Agora, considere outra aula 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 - declara apenas 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á a NullReferenceException.
Bem, em termos simples:
Você está tentando acessar um objeto que não foi criado ou atualmente não está na memória.
Então, como lidar com isso:
Depure e deixe o depurador quebrar ... Ele levará você diretamente para a variável que está quebrada ... Agora sua tarefa é simplesmente corrigir isso. Usando a nova palavra-chave no local apropriado.
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 tratá-lo:
if (i == null) {
// Handle this
}
O mais difícil .. se o GC já coletou o objeto ... Isso geralmente ocorre se você estiver tentando encontrar um objeto usando cadeias ... Ou seja, localizando-o pelo nome do objeto, pode ser que o GC já esteja limpo ... Isso é difícil de encontrar e se tornará um problema ... Uma maneira melhor de resolver isso é fazer verificações nulas sempre que necessário durante o processo de desenvolvimento. Isso economizará muito tempo.
Ao encontrar pelo nome, quero dizer que alguma estrutura permite que você FIndObjects use seqüências de caracteres e o código fique assim: FindObject ("ObjectName");
Literalmente, a maneira mais fácil de corrigir uma NullReferenceExeption tem duas maneiras. Se você tiver um GameObject, por exemplo, com um script anexado e uma variável chamada rb (rigidbody), essa variável começará nula quando você iniciar o jogo.
É por isso que você obtém um NullReferenceExeption porque o computador não possui dados armazenados nessa variável.
Vou usar uma variável RigidBody como exemplo.
Podemos adicionar dados com muita facilidade, de várias maneiras:
rb = GetComponent<Rigidbody>();
Start()
ou Awake()
. rb = AddComponent<RigidBody>();
Notas adicionais: Se você deseja que a unidade adicione um componente ao seu objeto e pode ter esquecido de adicioná-lo, digite [RequireComponent(typeof(RigidBody))]
acima da sua declaração de classe (o espaço abaixo de todos os seus usos).
Aproveite e divirta-se fazendo jogos!
Se considerarmos cenários comuns em que essa exceção pode ser lançada, acessando propriedades dentro do objeto na parte superior.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
aqui, se o endereço for nulo, você receberá NullReferenceException.
Portanto, 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
Isso é basicamente uma exceção de referência nula . Como a Microsoft declara
Uma exceção NullReferenceException é lançada quando você tenta acessar um membro de um tipo cujo valor é nulo.
Isso significa que, se algum membro que não possui nenhum valor e nós o obrigarmos a executar determinada tarefa, o sistema sem dúvida lançará uma mensagem e dirá:
"Ei, espere, esse membro não tem valores, portanto não pode executar a tarefa que você está entregando."
A própria exceção diz que algo está sendo referido, mas cujo valor não está sendo definido. Portanto, isso indica que isso ocorre apenas ao usar tipos de referência, pois os tipos Value não podem ser nulos.
NullReferenceException não ocorrerá se estivermos usando membros do tipo Valor.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
O código acima mostra uma sequência simples que é atribuída com um valor nulo .
Agora, quando tento imprimir o comprimento da string str , recebo uma mensagem sem exceção do tipo 'System.NullReferenceException', porque o membro str está apontando para nulo e não pode haver nenhum tamanho nulo.
' NullReferenceException ' também ocorre quando esquecemos de instanciar um tipo de referência.
Suponha que eu tenha um método de classe e membro. Não instanciei minha classe, mas apenas nomeiei minha classe. Agora, se eu tentar usar o método, o compilador lançará um erro ou emitirá um aviso (dependendo do compilador).
class Program
{
static void Main(string[] args)
{
MyClass1 obj;
obj.foo(); //Use of unassigned local variable 'obj'
}
}
public class MyClass1
{
internal void foo()
{
Console.WriteLine("hello from foo");
}
}
O compilador para o código acima gera um erro de que a variável obj não está atribuída, o que significa que nossa variável tem valores nulos ou nada. O compilador para o código acima gera um erro de que a variável obj não está atribuída, o que significa que nossa variável tem valores nulos ou nada.
NullReferenceException surge devido a nossa falha por não verificar o valor do objeto. Geralmente, deixamos os valores do objeto desmarcados no desenvolvimento do código.
Também surge quando esquecemos de instanciar nossos objetos. O uso de métodos, propriedades, coleções etc. que podem retornar ou definir valores nulos também pode ser a causa dessa exceção.
Existem várias maneiras e métodos para evitar essa renomada exceção:
Verificação explícita: Devemos seguir a tradição de verificar os objetos, propriedades, métodos, matrizes e coleções, sejam eles nulos. Isso pode ser simplesmente implementado usando instruções condicionais como if-else se-else etc.
Tratamento de exceções: uma das maneiras importantes de gerenciar essa exceção. Usando blocos simples try-catch-finalmente, podemos controlar essa exceção e também manter um log dela. Isso pode ser muito útil quando seu aplicativo estiver no estágio de produção.
Operadores nulos: O operador nulo de coalescência e os operadores condicionais nulos também podem ser úteis ao definir valores para objetos, variáveis, propriedades e campos.
Depurador: Para os desenvolvedores, temos a grande arma de depuração conosco. Se enfrentamos NullReferenceException durante o desenvolvimento, podemos usar o depurador para chegar à fonte da exceção.
Método interno: métodos do sistema, como GetValueOrDefault (), IsNullOrWhiteSpace () e IsNullorEmpty (), procuram nulos e atribuem o valor padrão se houver um valor nulo.
Já existem muitas boas respostas aqui. Você também pode verificar uma descrição mais detalhada com exemplos no meu blog .
Espero que isso ajude também!
Se alguém receber esta mensagem durante o salvamento ou compilação da compilação, feche todos os arquivos e abra qualquer arquivo para compilar e salvar.
Para mim, o motivo foi que eu havia renomeado o arquivo e o arquivo antigo ainda estava aberto.