O que é um NullReferenceException e como corrigi-lo?

1875

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?

John Saunders
fonte
O auxiliar de exceção no VS 2017 será mais útil no diagnóstico da causa dessa exceção - blogs.msdn.microsoft.com/visualstudio/2016/11/28/… em New Exception Helper .
Zev Spitz
Caros futuros visitantes, as respostas a esta pergunta se aplicam igualmente a uma ArgumentNullException . Se sua pergunta foi encerrada como uma duplicata desta e você está enfrentando uma ANE, siga as instruções nas respostas para depurar e corrigir seu problema.
@ ANE só deve acontecer se um nulo for passado como parâmetro. Você pode dar um exemplo se uma pergunta da ANE for fechada como duplicata desta?
John Saunders
Ele apareceu no Meta, mas eu teria que procurar o link. Mas, quanto a esse comentário, um ANE é simplesmente um NRE, mas alguém adicionou uma verificação preventiva, e você pelo menos sabe exatamente o que é nulo (o nome do argumento é fornecido), por isso é um pouco mais fácil de diagnosticar do que um NRE direto.

Respostas:

2415

Qual é a causa?

Bottom Line

Você está tentando usar algo que é null(ou Nothingno VB.NET). Isso significa que você deve defini-lo como nullou 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:

    1. Variáveis ​​de objeto que não foram inicializadas e, portanto, não apontam para nada. Nesse caso, se você acessar propriedades ou métodos de tais objetos, isso causará a NullReferenceException.
    1. O desenvolvedor está usando nullintencionalmente 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 nulla 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 aeste exemplo, permitem acessar o valor via a.Valueexplicitamente, ou apenas como via normal a.
      Observe que acessá-lo via a.Valuelança um em InvalidOperationExceptionvez de um NullReferenceExceptionse 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.

Mais especificamente

O runtimejogando 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 é nulle você não pode acessar membros (como métodos) por meio de uma nullreferência. O caso mais simples:

string foo = null;
foo.ToUpper();

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

Depuração

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.

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 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.Currentpoderia ser nulo ou a Userpropriedade poderia ser nula ou a Identitypropriedade poderia 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ê deseja evitar a referência nula filho (Pessoa), você pode inicializá-la no construtor do objeto pai (Livro).

Inicializadores de objetos aninhados

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 newpalavra-chave é usada, ela cria apenas uma nova instância de Book, mas não uma nova instância Person, portanto Authora propriedade permanece imóvel null.

Inicializadores de coleção aninhados

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

A coleção aninhada Initializersse 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 Bookscoleção ainda é null. A Initializersintaxe da coleção não cria uma coleção para p1.Books, ela se traduz apenas nas p1.Books.Add(...)instruções.

Matriz

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

Elementos da 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 intervalo (indireto / diferido)

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

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

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 do 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 exibição vazia do ASP.NET MVC

Se a exceção ocorrer ao fazer referência a uma propriedade de @Modelem um ASP.NET MVC View, você precisará entender que isso Modelé definido no seu método de ação, quando você returnvisualiza. 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 -->

Ordem de criação de controle WPF e eventos

WPFOs controles são criados durante a chamada InitializeComponentna ordem em que aparecem na árvore visual. A NullReferenceExceptionserá gerado no caso de controles criados anteriormente com manipuladores de eventos etc., aquele disparo durante o InitializeComponentqual 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_SelectionChangedtentar 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 label1antes comboBox1, ignorando questões da filosofia do design, pelo menos resolveria o problema NullReferenceExceptionaqui).

Elenco com as

var myThing = someObject as Thing;

Isso não InvalidCastExceptiongera um, mas retorna a nullquando o elenco falha (e quando someObjecté nulo). Então, fique ciente disso.

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

para cada

foreachlança quando você tenta iterar a coleção nula. Geralmente causado por nullresultado 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"))

Maneiras de evitar

Verifique explicitamente nulle ignore valores nulos.

Se, às vezes, você espera que a referência seja nula, verifique nullantes de acessar os membros da instância:

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

Verifique explicitamente nulle 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;
}

Verifique explicitamente as nullchamadas 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;
}

Use Debug.Assertse 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 == nullem tempo de execução no modo de liberação.

Use GetValueOrDefault()para nullabletipos 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

Use o operador coalescente nulo: ??[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;
}

Use o operador de condição nula: ?.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 ToUpperuma propriedade com um valor nulo.

Dentro C# 5e 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 ToUppernão será feita, se person.Titlefor null.

Obviamente, você ainda precisa verificar se titlehá 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 myIntArrayfor 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.

Use o contexto nulo (disponível em C # 8):

Introduzido nos C# 8contextos 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 Nullableelemento no seu csprojarquivo. Este elemento configura como o compilador interpreta a nulidade dos tipos e quais avisos são gerados. As configurações válidas são:

  • enable: O contexto de anotação anulável está ativado. O contexto de aviso anulável está ativado. Variáveis ​​de um tipo de referência, sequência por exemplo, não são anuláveis. Todos os avisos de nulidade estão ativados.
  • desativar: O contexto de anotação anulável está desativado. O contexto de aviso anulável está desativado. Variáveis ​​de um tipo de referência são inconscientes, assim como as versões anteriores do C #. Todos os avisos de nulidade estão desativados.
  • safeonly: o contexto de anotação anulável está ativado. O contexto de aviso anulável é seguro. Variáveis ​​de um tipo de referência não são anuláveis. Todos os avisos de nulidade de segurança estão ativados.
  • avisos: O contexto de anotação anulável está desativado. O contexto de aviso anulável está ativado. Variáveis ​​de um tipo de referência são inconscientes. Todos os avisos de nulidade estão ativados.
  • safeonlywarnings: o contexto de anotação anulável está desativado. O contexto de aviso anulável é seguro. Variáveis ​​de um tipo de referência são inconscientes. Todos os avisos de nulidade de segurança estão ativados.

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.

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

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 whateveros resultados em nullseguida, MakeFrobvai 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 GetFrobssimplesmente 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 é GetFrobsForRealexecutada quando a sequência é iterada.

Se você examinar a fonte de referência para LINQObjetos, 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 .

Uma observação sobre dereferences nulos em código não seguro

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:

  • desreferenciar um ponteiro nulo produz a mesma exceção que desreferenciar uma referência nula
  • desreferenciar 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ê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, CLRele 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.

LopDev
fonte
55
Talvez esse seja um comentário idiota, mas a primeira e melhor maneira de evitar esse problema seria inicializar o objeto? Para mim, se esse erro ocorre, geralmente é porque esqueci de inicializar algo como o elemento da matriz. Eu acho que é muito menos comum definir o objeto como nulo e depois fazer referência a ele. Talvez seja o caminho para resolver cada problema adjacente à descrição. Ainda é um bom post.
JPK
30
E se não houver objeto, mas o valor de retorno de um método ou propriedade?
John Saunders
6
O exemplo do livro / autor é um pouco estranho ... Como isso é compilado? Como o intellisense funciona? O que é isso, eu não sou bom com computar ...
5
@ Will: minha última edição ajuda? Caso contrário, seja mais explícito sobre o que você vê como um problema.
John Saunders
6
@ JohnSaunders Oh, não, desculpe, eu quis dizer a versão inicializadora de objetos disso. 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?
311

Exceção NullReference - Visual Basic

O NullReference Exceptionpara 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:

  1. Isso é baseado em conceito: não há código para você colar no seu projeto. Destina-se a ajudá-lo a entender o que causa um 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.
  2. Os exemplos (das postagens Stack Overflow) 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 não a inicializou (crie uma instância ou ' instancie ')
  • Algo que seu código assumiu inicializaria um objeto, não
  • Possivelmente, outro código invalidou prematuramente um objeto ainda em uso

Encontrando a causa

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.

Exibição de depuração do IDE

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

Exemplos e Remédios

Objetos de classe / Criando uma instância

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

O problema é que Dimnão cria um objeto CashRegister ; apenas declara uma variável denominada regdesse tipo. Declarar uma variável de objeto e criar uma instância são duas coisas diferentes.

Remédio

O Newoperador 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 Dimnovamente 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 regvariável com o nível do módulo Scopeque você usará em qualquer outro lugar permanece Nothing.

A falta do Newoperador é 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 o NewOperador 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) 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 | Publicdefine o nível de acesso, não o escopo .

Para mais informações, veja:


Matrizes

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 Newsã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 Fooobjetos 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:


Listas e Coleções

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 - myListfoi 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 Footambé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 .


Objetos do provedor de dados

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 dsobjeto Conjunto de dados foi declarado, mas uma instância nunca foi criada. O DataAdapterirá preencher um existente DataSet, não criar um. Nesse caso, como dsé uma variável local, o IDE avisa que isso pode acontecer:

img

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: Employeesvs Employee. Não havia um DataTablenome "Funcionário" criado; portanto, um NullReferenceExceptionresultado está tentando acessá-lo. Outro problema em potencial é supor que haverá o Itemsque 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.Counttambé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 Rowsafetados 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 DataAdapterserá fornecido TableNamescomo 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 .


Caminhos de Objeto / Aninhados

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

O código está testando apenas Itemsenquanto ambos myFooe Bartambé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 Falsecondiçã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.Barsomente depois que (e se) myFoofor 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 nullobjeto. Isso também se aplica aos controles:

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

Aqui, myWebBrowserou Documentpoderia ser Nothing ou o formfld1elemento 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 possa não ter selecionado algo em um ou mais controles da interface do usuário. ListBox1.SelectedItempode muito bem ser Nothing, então ListBox1.SelectedItem.ToStringresultará em um NRE.

Remédio

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


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

Essa é uma maneira bastante comum de obter um NRE. Em C #, dependendo de como é codificado, o IDE relatará que Controlsnã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 Formou o Controls. Como um resultado:

  • Listas e coleções simplesmente ficarão vazias
  • A matriz conterá cinco elementos de Nothing
  • A somevaratribuição resultará em uma NRE imediata porque Nothing não possui uma .Textpropriedade

A 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 Newou Form Loadevento), 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 Newou Form Loadserá 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 Newdesde que seu código seja 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 do array ainda pode não estar fora de perigo. Quaisquer controles que estejam em um controle de contêiner (como um GroupBoxou 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, Nothingserá 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: O VS mostra o erro de seus caminhos

"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

É um caso em que o IDE avisa que ' nem todos os caminhos retornam um valor e NullReferenceExceptionpodem resultar '. Você pode suprimir o aviso, substituindo Exit Functionpor Return Nothing, mas isso não resolve o problema. Qualquer coisa que tentar usar o retorno quando someCondition = Falseresultará em um NRE:

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

Remédio

Substitua Exit Functionna 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...

Try / Catch mal implementado

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 Catchnão fazer nada, Finallytenta executar a limpeza, mas como você não pode Closeum DataReaderobjeto nulo , NullReferenceExceptionresulta em um novo resultado.

Um Catchbloco vazio é o playground do diabo. Este OP ficou confuso por que ele estava recebendo um NRE no Finallybloco. Em outras situações, um vazio Catchpode 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.


DBNull não é o mesmo que Nothing

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

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 a GroupBox), chkserá Nothing e tentar fazer referência a 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 as referenciar por nome.

Remédio

Nomeie as colunas manualmente ou faça 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 você DataGridViewtiver AllowUserToAddRowscomo True(o padrão), o campo Cellsem 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/Eachloop e teste a IsNewRowpropriedade 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 nloop, modifique a contagem de linhas ou use Exit Forquando IsNewRowfor verdadeiro.


My.Settings (StringCollection)

Sob certas circunstâncias, tentar usar um item do My.Settingsqual é um StringCollectionpode 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 Nothingquando não há itens no editor de Configurações a serem adicionados.

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


Pontos chave

Você provavelmente esqueceu o Newoperador.

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


Exceção NullReference do MSDN

Plutonix
fonte
226

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 NullReferenceExceptionno 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 SelectedDatefato , é uma propriedade - do DateTimetipo - do tipo CalendarWeb 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 NullReferenceExceptionque é bastante difícil de detectar, porque está no código gerado pelo ASP.NET que compila bem ...

Simon Mourier
fonte
7
Ótima captura. Forma de uma linha para evitar:DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Serge Shultz
160

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:

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

Chris B. Behrens
fonte
3
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. Isto está incorreto. Eu tenho uma solução sem essa detecção, mas o código ocasionalmente resulta na exceção. Eu suspeito que às vezes seja indetectável - pelo menos por eles - quando o multithreading está envolvido, mas não posso comentar mais porque ainda não identifiquei a localização do meu bug.
j riv
Mas como resolvê-lo quando a NullReferenceException entrar em uso HttpContext.Current.Responce.Clear (). Não está sendo resolvido por nenhuma das soluções acima. porque ao criar seu objeto objeto de HttpContext, surge um erro "A resolução da sobrecarga falhou porque nenhum 'Novo' acessível aceita esse número de argumentos.
Sunny Sandeep
158

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
}
Jonathan Wood
fonte
96

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/ nullpara 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/ nullmanualmente ou chamou uma função que definiu a variável para Nothing/ nullpara você.

mestre de código
fonte
87

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 .

Alex KeySmith
fonte
87

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

  • dinâmico
  • objeto
  • corda

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

  • Tipos numéricos
  • Tipos integrais
  • Tipos de ponto flutuante
  • decimal
  • bool
  • Estruturas definidas pelo usuário
Fabian Bigler
fonte
6
-1: como a pergunta é "O que é uma NullReferenceException", os tipos de valor não são relevantes.
John Saunders
21
@ John Saunders: Eu discordo. Como desenvolvedor de software, é realmente importante ser capaz de distinguir entre tipos de valor e referência. caso contrário, as pessoas acabarão verificando se números inteiros são nulos.
Fabian Bigler
5
É verdade, mas não no contexto desta questão.
John Saunders
4
Obrigado pela dica. Melhorei um pouco e adicionei um exemplo no topo. Eu ainda acho que mencionar tipos de referência e valor é útil.
Fabian Bigler
5
Acho que você não adicionou nada que não estivesse nas outras respostas, pois a pergunta supõe um tipo de referência.
John Saunders
78

Outro caso em NullReferenceExceptionsque isso pode acontecer é o uso (incorreto) do asoperador :

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 Booke Carsão tipos incompatíveis; a Carnão pode ser convertido / convertido em a Book. Quando esse elenco falha, asretorna null. O uso mybookapó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) {
   // ...
}
Jonathon Reinhart
fonte
2
Isso pode acontecer muito ao desembalar uma variável. Acho que isso acontece com frequência nos manipuladores de eventos depois de alterar o tipo do elemento da interface do usuário, mas esqueça de atualizar o code-behind.
Brendan
65

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

user1814380
fonte
1
Quão profundo! Eu nunca considerei a constante 'nula' um valor de referência. Então é assim que o C # abstrai um "NullPointer" hein? Por mais que eu lembre-se em C ++, um NPE pode ser causado por desreferenciar um ponteiro não inicializado (ou seja, tipo ref em c #) cujo valor padrão é um endereço que não está alocado para esse processo (em muitos casos, 0, especialmente nas versões posteriores do C ++ que inicializaram automaticamente, que pertencem ao sistema operacional - f com ele e morrem de bip (ou apenas pegue o sigkill com o qual o sistema operacional ataca seu processo)).
samis 31/07
64

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 myStringavaliado 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 str1foi nulo ou se str2foi 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

user2864740
fonte
59

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.ValueTypeou 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 é HasValueigual false a um tipo de referência pode fornecer uma nullreferê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.

Jeppe Stig Nielsen
fonte
42

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

AbhinavRanjan
fonte
41

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 HttpContextmencionadas pelo código em teste devem ser ridicularizadas.

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

John Saunders
fonte
40

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();
    }
}
Mukus
fonte
6
-1: trata apenas de um cenário único - o de dependências não inicializadas. Este é um cenário minoritário para NullReferenceException. A maioria dos casos é um mal-entendido simples de como os objetos funcionam. A seguir, as mais frequentes são outras situações em que o desenvolvedor assumiu que o objeto seria inicializado automaticamente.
John Saunders
Geralmente, a injeção de dependência não é usada para evitar NullReferenceException. Não acredito que você tenha encontrado um cenário geral aqui. De qualquer forma, se você editar sua resposta para ter mais estilo no estilo stackoverflow.com/a/15232518/76337 , removerei o voto negativo.
John Saunders
38

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 NullReferenceExceptioncasos resultantes 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 "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 .

Nick L.
fonte
2
Pensei em acrescentar isso porque ninguém mencionou isso e, na medida em que existe como uma abordagem, minha intenção era enriquecer o tópico.
Nick Louloudakis
2
Obrigado por enriquecer o tópico. Eu dei minha opinião sobre sua adição. Agora outros podem fazer o mesmo.
John Saunders
2
Eu pensei que isso era uma adição interessante ao tópico, uma vez que este é um tópico muito visto. Já ouvi falar de contratos de código antes e este foi um bom lembrete para considerar usá-los.
precisa saber é o seguinte
36

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:

  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 
Hemant Bavle
fonte
2
Isto está incorreto. 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á.
Kjartan
31

TL; DR: tente usar em Html.Partialvez deRenderpage


Eu estava começando Object reference not set to an instance of an objectquando 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.Partialcomeçar foi porque o Visual Studio às vezes lança linhas onduladas com aparência de erro embaixo Html.Partialse estiver dentro de um foreachloop 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 foreachloop 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.

Travis Heeter
fonte
Você queria Html.Partial, não@Html.Partial
John Saunders
Além disso, mostre qual linha lançou a exceção e por quê.
31415 John Saunders
O erro ocorreu no MyOtherView.cshtml, que eu não incluí aqui, porque o modelo não estava sendo enviado corretamente (era Null), então eu sabia que o erro estava em como eu estava enviando o modelo.
Travis Heeter
22

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 ArgumentNullExceptionuma exceção obviamente criada para esse propósito exato.

O construtor para o ArgumentNullExceptioneven 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, objserá 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 Tpara que você possa usá-lo em qualquer lugar que precisar. Por exemplo, você pode passar um Personobjeto 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 Valuepropriedade 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, nulltoda 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 Countryque possui uma propriedade chamada Statee assim por diante. Se country, State, County, ou Cityé nullentão address will benulo . Therefore you only have to check whetherendereço isnull`.

É 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).

Luis Perez
fonte
2
Nunca jogue NullReferenceException
John Saunders
@JohnSaunders ousa perguntar por quê? (Seriamente embora por quê?)
Luis Perez
2
NullReferenceException deve ser lançado pelo CLR. Isso significa que uma referência a um nulo ocorreu. Isso não significa que uma referência a um nulo ocorra, exceto que você foi habilmente verificado primeiro.
John Saunders
Entendo sua opinião sobre como isso seria confuso. Eu atualizei para uma exceção regular para este exemplo e uma exceção personalizada no GitHub.
Luis Perez
Ótima resposta para uma pergunta tão básica. Não é tão ruim quando seu código está falhando. É horrível quando está vindo de dentro de uma biblioteca comercial de terceiros em que você confia, e o suporte ao cliente continua insistindo que deve ser o seu código que está causando o problema. E você não tem certeza absoluta de que não é e todo o projeto é interrompido. Na verdade, acho que isso pode ser um epitáfio apropriado para minha lápide: "Referência de objeto não definida para uma instância de um objeto".
Darrel Lee 03/03
10

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

Caso 1 do Edge: acesso simultâneo a um dicionário

Dicionários genéricos no .NET não são seguros para threads e, às vezes, podem gerar um NullReferenceou até (mais frequente) umKeyNotFoundException quando você tenta acessar uma chave de dois threads simultâneos. A exceção é bastante enganosa neste caso.

Caso 2 do Edge: código não seguro

Se a NullReferenceExceptioné lançada pelo unsafecó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)

jazzcat
fonte
5
O exemplo do seu dicionário não é um caso de ponta. Se o objeto não for seguro para threads, usá-lo em vários threads produz resultados aleatórios. Seu exemplo de código inseguro difere de nullque maneira?
John Saunders
10

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

M.Hassan
fonte
9

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;  
     }
}
Jaimin Dave
fonte
4

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.

usuario
fonte
3

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:

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

  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 tratá-lo:

    if (i == null) {
        // Handle this
    }
  3. 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");

Akash Chowdary
fonte
3
Se você tem uma referência a um objeto, o GC nunca o limpa
John Saunders
2
se você usar coisas como FindObject ("Nome do objeto"), não há como a GC saber de antemão que você vai referenciar esse objeto .. é isso que estava tentando explicar .. isso ocorre em tempo de execução
Akash Gutha
2
Existem algumas estruturas que fornecem essa funcionalidade no C #, como o Unity. a questão não tem nada relacionado ao BCl. Pesquise na Internet antes de Criticar, existem inúmeras funções como elas e, para obter informações úteis, eu mesmo as uso diariamente. Agora, por favor, diga-me como a resposta não faz nenhum sentido.
Akash Gutha
2
docs.unity3d.com/ScriptReference/… verifique o link e corrija-se sr.expert: p
Akash Gutha
Os exemplos que vi no seu link atribuem os resultados do GameObject.Find a um campo de membro. Essa é uma referência e o GC não a coletará até que o objeto que contém seja coletado.
John Saunders
1

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:

  1. Adicione um RigidBody ao seu objeto com AddComponent> Physics> Rigidbody.
    Em seguida, entre no seu script e digite rb = GetComponent<Rigidbody>();
    Esta linha de código funciona melhor nas suas funções Start()ou Awake().
  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 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!

CausticLasagne
fonte
-1

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
Hiran
fonte
-3

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.

O que isso significa?

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.

Por que isso ocorre?

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

Como isso pode ser evitado?

Existem várias maneiras e métodos para evitar essa renomada exceção:

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

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

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

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

  5. 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!

Wasim
fonte
Você basicamente copiou metade dessa postagem no blog e não adicionou nada novo que as respostas existentes não abordam.
CodeCaster
@ codecaster Diz-se copiar quando você reescreve um resumo do seu próprio blog. Sei que não há nada de novo na minha resposta e nada de novo que as respostas anteriores não tenham, mas desejo contribuir de maneira mais sofisticada e deixar que os outros entendam da maneira que eu entendi. Ficará feliz, mesmo que ajude uma única pessoa. Em boa fé.
Wasim
-4

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.

Harshal Doshi Jain
fonte