Pregunta Detectando cuál es el objeto objetivo cuando se lanza NullReferenceException


Estoy seguro de que todos hemos recibido la maravillosa y vaga excepción "Referencia de objeto no configurada a instancia de un Objeto" en algún momento u otro. Identificar el objeto que es el problema a menudo es una tarea tediosa de establecer puntos de interrupción e inspeccionar a todos los miembros en cada declaración.

¿Alguien tiene algún truco para identificar de manera fácil y eficiente el objeto que causa la excepción, ya sea a través de medios programáticos o de otro modo?

--editar

Parece que fui vago como la excepción =). El punto es _no tener que depurar la aplicación para encontrar el objeto errante. El compilador / tiempo de ejecución sabe que el objeto ha sido asignado / declarado, y que el objeto aún no ha sido instanciado. ¿Hay alguna forma de extraer / identificar esos detalles en una excepción atrapada?

@ W. Craig Trader

Su explicación de que es el resultado de un problema de diseño es probablemente la mejor respuesta que podría obtener. Soy bastante compulsivo con la codificación defensiva y he logrado deshacerme de la mayoría de estos errores después de corregir mis hábitos con el tiempo. Los restantes solo retocar sin fin, y me llevan a publicar esta pregunta a la comunidad.

Gracias por las sugerencias de todos.


28
2017-09-22 15:35


origen


Respuestas:


En el punto donde se arroja el NRE, no hay un objeto objetivo, ese es el punto de la excepción. Lo máximo que puede esperar es atrapar el archivo y el número de línea donde ocurrió la excepción. Si tiene problemas para identificar qué referencia de objeto está causando el problema, entonces quizás desee replantear sus estándares de codificación, ya que parece que está haciendo demasiado en una línea de código.

Una mejor solución para este tipo de problema es Diseño por contrato, ya sea a través de construcciones de lenguaje incorporado, o a través de una biblioteca. DbC sugeriría verificar previamente cualquier argumento entrante para un método de datos fuera de rango (es decir: nulo) y lanzar excepciones porque el método no funcionará con datos incorrectos.

[Editar para hacer coincidir la edición de la pregunta:]

Creo que la descripción de NRE te está engañando. El problema que tiene el CLR es que se le solicitó que desreferenciara una referencia de objeto, cuando la referencia del objeto es nula. Toma este programa de ejemplo:

public class NullPointerExample {
  public static void Main()
  {
    Object foo;
    System.Console.WriteLine( foo.ToString() );
  }
}

Cuando ejecuta esto, lanzará un NRE en la línea 5, cuando intente evaluar el método ToString () en foo. No hay objetos para depurar, solo una referencia de objeto no inicializada (foo). Hay una clase y un método, pero no hay objeto.


Re: Chris Marasti-Georg's responder:

Nunca debe arrojar NRE usted mismo - esa es una excepción del sistema con un significado específico: el CLR (o JVM) ha intentado evaluar una referencia de objeto que no se inicializó. Si realiza una comprobación previa de una referencia de objeto, puede lanzar algún tipo de excepción de argumento no válido o una excepción específica de la aplicación, pero no NRE, ya que solo confundirá al siguiente programador que debe mantener su aplicación.


16
2017-09-22 16:00



Como han señalado algunas respuestas, dígale a Visual Studio que se rompa en Throw for NullReferenceException.

Cómo decirle a VS que se rompa cuando se lanzan excepciones no controladas

  • Menú de depuración | Excepciones (o Ctrl + Alt + mi)
  • Taladre en las excepciones de Common Language Runtime
  • Taladrar en el sistema
  • Busque System.NullRefernceException y marque la casilla para romper cada vez que se lanza esta excepción, en lugar de permitir que proceda a los bloques de captura que estén en su lugar.

Entonces, cuando ocurra, VS se romperá de inmediato, y la línea de Declaración actual estará asentada en la expresión que se evaluó como nula.

Esta función es útil para todo tipo de excepciones, incluidas las personalizadas (puede agregar el nombre de tipo completo y VS lo igualará en tiempo de depuración)

El único inconveniente de este enfoque es si hay un código cargado en el depurador que sigue la mala práctica de arrojar y capturar muchas de las excepciones que está buscando, en cuyo caso se convierte nuevamente en un problema de pajar / aguja (a menos que pueda arregla ese código, por supuesto, entonces has resuelto dos problemas :)


Otro truco que puede ser útil (pero solo en algunos idiomas) es el uso de la palabra clave When (o equivalente) ... En VB, esto parece

Try
  ' // Do some work           '
Catch ex As Exception When CallMethodToInspectException(ex)

End Try

El truco aquí es que la expresión Cuando se evalúa antes de que la pila de llamadas se desenrolle en el bloque Catch. Entonces, si está utilizando el depurador, puede establecer un punto de interrupción para esa expresión, y si observa la ventana de la pila de llamadas (Depurar | Windows | Pila de llamadas), puede ver y navegar hasta la línea que activó la excepción.

(Puede elegir devolver falso desde CallMethodToInspectException, por lo que se ignorará el bloque Catch y el tiempo de ejecución continuará la búsqueda a través de la pila para un bloque Catch apropiado, lo que puede permitir el registro que no afecta el comportamiento y con una menor sobrecarga que una captura y re-lanzamiento)


Si estuviera interesado en el registro no interactivo, suponiendo que tiene una compilación de depuración (o, en cierta medida, ya que tiene que lidiar con problemas de optimización, compilación de versión con PDB), puede obtener la mayor parte de la información necesaria para rastrear el error de Exception ToString, con el stack-trace-with-line-number incluido.

Sin embargo, si el número de línea no fuera suficiente, también puede obtener el número de columna (por lo tanto, la expresión local o local nula) extrayendo StackTrace para la excepción (utilizando la técnica anterior o simplemente en el bloque catch) sí mismo):

int colNumber = new System.Diagnostics.StackTrace(ex, true).GetFrame(0).GetFileColumnNumber();

Si bien no he visto lo que hace para NullReference u otras excepciones generadas en el tiempo de ejecución, también podría estar interesado en mirar Cazador de excepciones como una herramienta de análisis estático.


15
2017-09-22 18:00



No hay mucho que puedas hacer además de mirar el rastro de la pila; si desreferencia referencias de objetos múltiples en la misma línea de código, no hay manera de determinar cuál es nulo sin establecer un punto de interrupción. Podrías evitar esto desmarcando solo un objeto por línea, pero eso daría como resultado un código bastante terrible.


1
2017-09-22 15:39



Bueno, realmente no se puede identificar el objeto ya que no existe y, por lo tanto, se trata de la excepción que se está obteniendo.


1
2017-09-22 15:39



La línea # y el archivo son generalmente todo lo que necesita para encontrar al culpable. Si eres el que lanza la excepción, considera usar un ArgumentNullException, si corresponde, o verificar nulos y tirar NullReferenceExceptions que tienen más detalles sobre el campo nulo.

Edita @ tu edición :)

AFAIK, tendría que examinar la cadena de seguimiento de pila para obtener esa línea # y archivo. Su mejor opción sería obtener la excepción más interna y luego mirar la primera línea de su rastro de pila. Si desea poder analizar programáticamente esa información para averiguar qué campo causó el nulo y hacer algo con el nombre de ese campo, me temo que no tendrá suerte.

@W. Craig Trader

Buen punto. Para un valor nulo que se pasa al método, un ArgumentNullException debe ser arrojado. Para una variable miembro que aún no se ha inicializado, algo así como InvalidStateException probablemente sería bueno tirar. Lamentablemente, no puedo encontrar ninguna excepción en MSDN. Hazlo tu mismo?


1
2017-09-22 15:41



puede verificar las propiedades Message e InnerException

http://msdn.microsoft.com/en-us/library/system.exception.innerexception.aspx


0
2017-09-22 15:39



Si está detectando excepciones para mensajes de usuario amigables o para iniciar sesión, probablemente desee que el depurador se detenga en una excepción durante la depuración. Vaya a Depurar / Excepciones y compruebe los tipos de excepción para los que desea que el depurador deje de ejecutarse, System.NullReferenceException en su caso.


0
2017-09-22 15:43



Establezca VS para romper con las excepciones, luego cuando obtiene su error, generalmente es bastante obvio en qué línea está. La ventana de rastreo de pila le dirá cómo llegó allí. No hay mucho más que puedas hacer aparte de eso.


0
2017-09-22 15:46



Como referencia, un hilo similar:¿Debo detectar excepciones solo para registrarlas?

Lo más destacado es que desea capturar de manera efectiva la excepción. En mi experiencia, el objetivo es asegurarme de que el programador verifique las referencias nulas en el código; sin embargo, sabemos que, en realidad, echamos de menos algunas. El código de UI debe tener cierto nivel de manejo de excepciones. Me gustó mi respuesta a esa pregunta: Mi respuesta. Más importante aún, el comentario de 1800 información, quien señaló que simplemente tira, y no arroja ex para capturar el seguimiento completo de la pila, que es la forma en que se solucionan estos problemas.


0
2017-09-22 17:25