Подтвердить что ты не робот

Почему не может исключить исключение с помощью null-reference объекта, который имеет нулевую ссылку?

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

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.

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

Для таких языков, как 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 в примере, не может и не знает, откуда эта нулевая ссылка.

Ответ 3

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

Ответ 4

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

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

Ответ 5

Несколько вещей...

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

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

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

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

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