Estamos lançando um sistema e, às vezes, recebemos a famosa exceção NullReferenceException
com a mensagem Object reference not set to an instance of an object
.
No entanto, em um método em que temos quase 20 objetos, ter um log que diz que um objeto é nulo é realmente inútil. É como dizer a você, quando você é o agente de segurança de um seminário, que um homem entre cem participantes é um terrorista. Isso é realmente inútil para você. Você deve obter mais informações, se quiser detectar qual homem é o homem ameaçador.
Da mesma forma, se quisermos remover o bug, precisamos saber qual objeto é nulo.
Agora, algo ficou obcecado por vários meses, e é isso:
Por que o .NET não nos fornece o nome ou, pelo menos, o tipo de referência do objeto, que é nulo? . Não consegue entender o tipo de reflexão ou qualquer outra fonte?
Além disso, quais são as melhores práticas para entender qual objeto é nulo? Devemos sempre testar a nulidade de objetos nesses contextos manualmente e registrar o resultado? Existe uma maneira melhor?
Atualização:
a exceção The system cannot find the file specified
tem a mesma natureza. Você não pode encontrar qual arquivo, até anexar ao processo e depurar. Eu acho que esses tipos de exceções podem se tornar mais inteligentes. Não seria melhor se o .NET nos dissesse em c:\temp.txt doesn't exist.
vez dessa mensagem geral? Como desenvolvedor, voto sim.
fonte
new
para criar instâncias de uma classe. Quando essa dica realmente ajuda?Respostas:
O
NullReferenceException
basicamente diz a você: você está fazendo errado. Nada mais nada menos. Não é uma ferramenta de depuração completa, pelo contrário. Nesse caso, eu diria que você está fazendo errado, porqueSou um grande fã de verificar tudo antes que as coisas comecem a dar errado e fornecer boas informações ao desenvolvedor. Em resumo: escreva cheques usando
ArgumentNullException
e os gostos e escreva o nome você mesmo. Aqui está uma amostra:Você também pode procurar por contratos de código , ele possui peculiaridades, mas funciona muito bem e economiza algumas digitações.
fonte
I only say that checking every object to get sure that it's not null, is not a good method
Seriously. É o melhor método. E não apenas nulo, verifique todos os argumentos em busca de valores razoáveis. Quanto mais cedo você detectar erros, mais fácil será encontrar a causa. Você não precisa voltar atrás em vários níveis no rastreamento de pilha para encontrar a chamada causadora.Realmente deve mostrar exatamente o que você está tentando chamar. É como dizer "Há um problema. Você precisa corrigi-lo. Eu sei o que é. Eu não vou lhe contar. Você vai descobrir" É como metade das respostas neste estouro de pilha, ironicamente.
Então, como seria útil, por exemplo, se você entendesse isso ...
...? Ter que entrar no código, percorrê-lo e descobrir que o que você está tentando chamar
null
é bom, mas por que não nos dar uma pequena ajuda?Concordo que geralmente é útil percorrer o código para chegar à resposta (porque você provavelmente descobrirá mais), mas muitas vezes muito tempo e frustração seriam salvos se o
NullReferenceException
texto fosse mais parecido com o exemplo acima.Apenas dizendo.
fonte
KeyNotFoundException
e muitos outros aborrecimentos ...Seu log deve incluir um rastreamento de pilha - que geralmente fornece uma dica sobre qual linha do método tem o problema. Pode ser necessário fazer com que sua compilação de versão inclua símbolos PDB para ter uma ideia de qual linha está o erro.
Concedido, não o ajudará neste caso:
O princípio tell don't ask pode ajudar a evitar esse código.
Quanto ao motivo pelo qual as informações não estão incluídas, não tenho certeza - suspeito que pelo menos em uma compilação de depuração, se eles realmente quisessem, poderiam descobrir. Tomar um despejo de memória e abrir no WinDBG pode ajudar.
fonte
Exceções foram criadas como uma ferramenta para sinalizar condições não fatais excepcionais na cadeia de chamadas. Ou seja, eles não foram projetados como uma ferramenta de depuração.
Se uma exceção de ponteiro nulo fosse uma ferramenta de depuração, abortaria a execução do programa no local, permitindo que um depurador se conectasse, apontando-o diretamente na linha incriminadora. Isso daria ao programador todas as informações de contexto disponíveis. (Que é basicamente o que um Segfault devido a um acesso nulo ao ponteiro faz em C, embora um pouco grosseiro.)
No entanto, a exceção de ponteiro nulo é projetada como uma condição de tempo de execução válida que pode ser lançada e capturada no fluxo normal do programa. Consequentemente, considerações de desempenho precisam ser levadas em consideração. E qualquer personalização da mensagem de exceção requer que objetos de cadeia sejam criados, concatenados e destruídos no tempo de execução. Como tal, uma mensagem estática é indiscutivelmente mais rápida.
Não estou dizendo que o tempo de execução não pôde ser programado de uma maneira que produziria o nome da referência incriminadora. Isso poderia ser feito. Isso tornaria as exceções ainda mais lentas do que são. Se alguém se importasse o suficiente, esse recurso poderia ser alternado, para que não diminuísse o código de produção, mas permitisse uma depuração mais fácil; mas por alguma razão ninguém parece ter se importado o suficiente.
fonte
Acho que o cromulento acertou a cabeça, no entanto, também existe o ponto óbvio de que, se você está recebendo uma,
NullReferenceException
possui variáveis não inicializadas. O argumento de que você tem cerca de 20 objetos sendo passados para um método não pode ser considerado uma atenuação: como criador de um pedaço de código, você deve ser responsável por suas ações, que inclui sua conformidade com o restante de uma base de código, como bem como a utilização correta e correta de variáveis, etc.é oneroso, tedioso e, às vezes, monótono, mas as recompensas no final valem a pena: muitas são as ocasiões em que tive que vasculhar arquivos de log com vários gigabytes e quase sempre são úteis. Entretanto, antes de chegar a esse estágio, o depurador pode ajudá-lo e, antes desse estágio, um bom planejamento poupará muita dor (e não quero dizer uma abordagem totalmente projetada para você codificar a solução: esboços simples e algumas anotações podem e vão seja melhor que nada).
Em relação ao
Object reference not set to an instance of an object
código, não podemos adivinhar os valores que podemos gostar: esse é o nosso trabalho como programadores e significa simplesmente que você passou uma variável não inicializada.fonte
Aprenda a usar o depurador. Este é exatamente o tipo de coisa para a qual foi projetado. Defina um ponto de interrupção no método em questão e pronto.
Basta percorrer seu código e ver exatamente quais são os valores de todas as suas variáveis em determinados pontos.
Edit: Francamente, estou chocado que ninguém mais tenha mencionado o uso do depurador ainda.
fonte
Se você quiser ir com a resposta de @ stijn e colocar verificações nulas no seu código, esse trecho de código deve ajudar. Aqui estão algumas informações sobre trechos de código . Depois de configurá-lo, basta digitar
argnull
, clicar na guia duas vezes e preencher o espaço em branco.fonte
nameof
que o seu trecho poderia serthrow new ArgumentNullException(nameof($argument$))
que tem as vantagens de não incluindo constantes mágicas, sendo verificada pelo compilador, e trabalhar melhor com refatoração ferramentas