2009-02-23 12 views
11

Me parece que una gran parte de mi tiempo de depuración se emplea para buscar excepciones de referencia nula en sentencias complejas. Por ejemplo:¿Por qué una excepción de referencia nula no puede nombrar el objeto que tiene una referencia nula?

For Each game As IHomeGame in _GamesToOpen.GetIterator() 

Por qué, cuando recibo una NullReferenceException, puedo obtener el número de línea en el seguimiento de la pila, pero no el nombre del objeto que es igual a cero. En otras palabras, por qué:

Object reference not set to an instance of an object. 

en lugar de

_GamesToOpen is not set to an instance of an object. 

o

Anonymous object returned by _GamesToOpen.GetIterator() is null. 

o

game was set to null. 

Es ésta estrictamente una opción de diseño, la intención de proteger el anonimato del código o hay una comp ¿El motivo en el diseño del compilador no incluye esta información en la excepción de tiempo de depuración?

Respuesta

11

Las excepciones son cosas del tiempo de ejecución, las variables son cosas del tiempo de compilación.

De hecho, la variable en su ejemplo es una expresión. Las expresiones no son siempre variables simples. En el tiempo de ejecución, la expresión se evaluará y se llamará al método sobre el objeto resultante. Si el valor de esa expresión es null, el tiempo de ejecución generará un NullReferenceException. Asumir la siguiente:

Dim a as New MyObject 
Dim b as String = MyObject.GetNullValue().ToString() 

¿Qué mensaje de error debería el retorno de tiempo de ejecución si el método devuelve GetNullValue()null?

+2

Los números de línea también son algo de tiempo de ejecución. La compilación de tiempo de depuración contiene todo tipo de cosas en tiempo de compilación (nombres de clase y método, números de línea, etc.) ¿Por qué no nombres variables? –

+1

Las clases y métodos y nombres de parámetros realmente existen en el nivel IL. Pero las variables prácticamente desaparecen en el IL generado. Básicamente, no hay una forma específica de relacionar una excepción con una variable específica: Asumir "if (a

+0

Aceptado debido al comentario anterior. –

1

Una forma simple de detectar esto para la depuración para colocar una declaración de Assert antes de usar un objeto, comprobar nulo y mostrar un mensaje significativo.

+0

No siempre es posible tener un Assert. Por ejemplo, no puede agregar una afirmación dentro de una expresión Linq. –

+0

Corrígeme si me equivoco, pero pensé que las afirmaciones de Assert se eliminan de las compilaciones de versiones optimizadas. – Marc

1

En compilaciones de versión, los nombres de variables se eliminan de los símbolos e incluso se puede optimizar el código para no tener una ubicación de memoria específica para una variable, pero simplemente mantener la referencia en uno de los registros (según el alcance del uso variable). Por lo tanto, es posible que no se pueda deducir el nombre de la variable de la ubicación de referencia.

En la construcción de depuración, hay más información disponible sobre las variables. Sin embargo, el objeto de excepción debe funcionar de la misma manera independientemente del sabor de compilación. Por lo tanto, actúa sobre la información mínima a la que puede acceder en cualquier sabor.

+0

Eso está bien. Probablemente no lo quiera en compilaciones de versiones de todos modos. Especifiqué en la pregunta que me preguntaba por qué no puedes ver esto en compilaciones de depuración. –

+0

Pensé que mencioné esto. Los objetos de excepción no son una función de depuración y deberían funcionar igual independientemente del sabor de compilación. No esperarías que el comportamiento de la clase String cambiara radicalmente en Debug Sabor, ¿o sí? –

1

Un par de cosas ...

1) cuando haga sus propias excepciones tenga esto en cuenta (si está molesto que es para esta otra persona va a ser molesto por que si lo hace para otra cosa) Dado que la ruta de excepción no debe ser en absoluto la ruta típica, el tiempo dedicado a hacer la excepción tiene información útil que bien vale la pena.

2) como un practive programación general adoptar este estilo y que tendrá muchos menos problemas (sí su código será más larga en términos de líneas, pero se ahorrará un montón de tiempo):

a) Nunca hacer ab(). c(); hacer x = a.b(); X.do(); (en líneas separadas) de esa manera puede ver que a era nulo o si el retorno de a.b() es nulo.

b) nunca pase la devolución de una llamada de método como parámetro - siempre pase variables. a (foo()); debería ser x = foo(); hacha); Este es más para la depuración y poder ver el valor.

No sé por qué los entornos como .net y Java no proporcionan una versión del tiempo de ejecución que tenga más información sobre este tipo de excepciones, como qué era el índice en una matriz fuera de los límites, el nombre de la variable cuando es nula, etc ...

2

para lenguajes como Java que se compila a código de bytes que consigue interpretado por una máquina virtual, suponga que tiene una clase X con un campo x, y su valor es null para una cierta referencia. Si se escribe

x.foo() 

el código de bytes podría tener este aspecto:

push Xref   >> top of stack is ref to instance of X with X.x = null 
getField x   >> pops Xref, pushes 'null' on the stack 
invokeMethod foo >> pops 'null' -> runtime exception 

El punto es que la operación que necesita una referencia no nula en la pila para operar en él, como InvokeMethod en el ejemplo , no puede y no sabe de dónde vino esa referencia nula.

Cuestiones relacionadas