Почему исключение с нулевой ссылкой не может назвать объект, имеющий нулевую ссылку?
Мне кажется, что много времени на отладку уходит на поиск исключений с нулевой ссылкой в сложных операторах. Например:
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)5
Исключения - это вещи времени выполнения, переменные - вещи времени компиляции.
Фактически, переменная в вашем примере является выражением . Выражения не всегда являются простыми переменными. Во время выполнения выражение будет оценено, и метод будет вызван для полученного объекта. Если значение этого выражения равно null
, среда выполнения выдаст файл NullReferenceException
. Предположим следующее:
Dim a as New MyObject
Dim b as String = MyObject.GetNullValue().ToString()
Какое сообщение об ошибке должна вернуть среда выполнения, если GetNullValue()
метод возвращается null
?
В сборках выпуска имена переменных удаляются из символов, и код может быть даже оптимизирован, чтобы не было определенного места в памяти для переменной, а просто сохранить ссылку в одном из регистров (в зависимости от области использования переменной. ). Таким образом, может оказаться невозможным вычесть имя переменной из ссылочного местоположения.
В отладочной сборке доступна дополнительная информация о переменных. Однако объект исключения должен работать одинаково независимо от типа сборки. Следовательно, он действует на основе минимального количества информации, к которой он может получить доступ в любом варианте.
Пару вещей ...
1) когда вы делаете свои собственные исключения, имейте это в виду (если вас это раздражает, то кто-то другой будет раздражаться на вас, если вы сделаете это для чего-то другого). Учитывая, что путь исключения вообще не должен быть типичным путем, время, потраченное на создание исключения, имеет полезную информацию, оно того стоит.
2) в качестве общей практики программирования используйте этот стиль, и у вас будет гораздо меньше проблем (да, ваш код будет длиннее с точки зрения строк, но вы сэкономите много времени):
а) никогда не выполняйте ab (). c (); сделать x = ab (); xc (); (в отдельных строках) таким образом вы можете увидеть, что a было null или если ab () возвращено null.
б) никогда не передавайте возврат вызова метода в качестве параметра - всегда передавайте переменные. а (foo ()); должно быть x = foo (); а (х); Это больше для отладки и возможности увидеть значение.
Я не знаю, почему такие среды, как .net и Java, не предоставляют версию среды выполнения, в которой есть дополнительная информация об этих видах исключений, например о том, какой индекс был в массиве за пределами границ, имя переменной, когда это ноль и т. д.
Для таких языков, как 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 в примере, не может и не знает, откуда взялась эта нулевая ссылка.