Почему исключение с нулевой ссылкой не может назвать объект с нулевой ссылкой? - PullRequest
12 голосов
/ 23 февраля 2009

Мне кажется, что я трачу много времени на отладку исключений с нулевыми ссылками в сложных операторах. Например:

For Each game As IHomeGame in _GamesToOpen.GetIterator()

Почему, когда я получаю исключение NullReferenceException, я могу получить номер строки в трассировке стека, но не имя объекта, равного нулю. Другими словами, почему:

Object reference not set to an instance of an object.

вместо

_GamesToOpen is not set to an instance of an object.

или

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

или

game was set to null.

Это строго проектный выбор, предназначенный для защиты анонимности кода, или в дизайне компилятора есть веская причина не включать эту информацию в исключение времени отладки?

Ответы [ 5 ]

11 голосов
/ 23 февраля 2009

Исключениями являются вещи времени выполнения, переменные - вещи времени компиляции.

Фактически, переменная в вашем примере это выражение . Выражения не всегда простые переменные. Во время выполнения выражение будет оценено, и метод будет вызван для результирующего объекта. Если значение этого выражения равно null, среда выполнения выдаст NullReferenceException. Предположим следующее:

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

Какое сообщение об ошибке должно возвращать среда выполнения, если метод GetNullValue() возвращает null?

2 голосов
/ 23 февраля 2009

Для таких языков, как Java, скомпилированных в байт-код, который интерпретируется виртуальной машиной, предположим, что у вас есть класс X с полем x, а его значение null для определенной ссылки. Если ты пишешь

x.foo()

байт-код может выглядеть следующим образом:

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

Дело в том, что операция, для работы с которой требуется ненулевая ссылка в стеке, как и invokeMethod в примере, не может и не знает, откуда взялась эта нулевая ссылка.

1 голос
/ 23 февраля 2009

Пара вещей ...

1) когда вы делаете свои собственные исключения, имейте это в виду (если вас это раздражает, то за вас это будет раздражать кого-то другого, если вы сделаете это для чего-то другого). Учитывая, что путь исключения не должен быть типичным путем, время, потраченное на создание исключения, имеет полезную информацию.

2) в качестве общей практики программирования используйте этот стиль, и у вас будет гораздо меньше проблем (да, ваш код будет длиннее с точки зрения строк, но вы сэкономите много времени):

a) никогда не делайте a.b (). C (); do x = a.b (); x.c (); (в отдельных строках), чтобы вы могли видеть, что a было пустым, или если возвращение a.b () пустым.

b) никогда не передавать возврат вызова метода в качестве параметра - всегда передавать переменные. а (Foo ()); должно быть x = foo (); а (х); Это больше для отладки и возможности увидеть значение.

Я не знаю, почему такие среды, как .net и Java, не предоставляют версию среды выполнения, в которой есть больше информации об этих видах исключений, таких как, например, индекс для массива вне границ, имя переменная, когда она равна нулю и т. д.

1 голос
/ 23 февраля 2009

В выпусках сборки имена переменных удаляются из символов, и код может быть даже оптимизирован, чтобы не иметь определенной области памяти для переменной, а просто сохранять ссылку в одном из регистров (в зависимости от области действия использование переменной). Таким образом, может быть невозможно вычесть имя переменной из ссылочного местоположения.

В отладочной сборке доступно больше информации о переменных. Однако объект исключения должен работать одинаково независимо от стиля сборки. Следовательно, он действует на минимальной информации, к которой он может получить доступ любым способом.

1 голос
/ 23 февраля 2009

Простой способ поймать это для отладки, чтобы поместить оператор Assert перед использованием объект, проверьте нулевое значение и выведите значимое сообщение.

...