Каково было конструктивное решение для NullReferenceException, не содержащее какой-либо конкретной информации о времени выполнения, кроме данных базового класса (например, stacktrace)? И есть ли расширение Visual Studio, которое может сразу сказать вам, какая часть выражения была нулевой?
Почему NullReferenceException содержит информацию о том, что является нулевым?
Ответ 1
NRE - это исключение на низком уровне. Это аппаратное исключение ( "ловушка" ), генерируемое процессором, когда ему предлагается читать данные с адреса ниже 64K. Эта область виртуальной памяти всегда не отображается, в частности, для улавливания ошибок указателя. Он запускается как AccessViolation и переходит в NRE с помощью CLR, когда адрес меньше 0x00010000. В этот момент существует очень мало контекста для исключения, все, что известно, является адресом инструкции машинного кода, которая вызвала ловушку.
Обратное проектирование того, что адрес команды машинного кода обратно к именованной переменной в вашей программе невозможен. Важно, чтобы он работал таким образом, джиттер должен был генерировать очень неэффективный код в противном случае. Все, что можно разумно сделать, это восстановить номер строки исходного кода. Для этого требуется информация для отладки (.pdb), которая содержит информацию о номере линии. CLR знает, как читать файл .pdb и использует его для генерации трассировки стека исключений. Тем не менее, это часто все еще неточно из-за оптимизации, выполняемой оптимизатором JIT, он перемещает код. Вы получите гарантированное соответствие для сборки Debug. Причина, по которой PDB для сборки Release не содержит информации о номере строки источника. Вы можете изменить это.
Эта проблема имеет очень простое решение. Проверьте нулевое значение и создайте собственное исключение, прежде чем позволить ему выполнить его. Тест довольно дешев, что значительно меньше, чем наносекунда.
Ответ 2
Вы можете настроить Visual Studio на немедленное прерывание Throw для NullReferenceException
, а не сначала в блоке catch.
- Debug
- Исключения
- Общий язык
- Система исключений времени выполнения
- System.NullReferenceException(установите флажок)
Тогда у вас будет разрыв строки, вызвавшей NullReferenceException
.
Ответ 3
Нет тривиального способа определить, что было нулевым во время выполнения - необходимая информация должна быть декомпилирована и выведена из IL, которая достаточно низкоуровневая, что все, что она знает, это то, что "элемент вверху stack имеет значение null", но не то, как этот элемент попал туда.
(И я не знаю такого расширения, но это было бы хорошим улучшением отладчика)
Ответ 4
NullReferenceException
вызывается средой выполнения, а не языком. Время выполнения не знает, где была ссылка; он просто знает, что инструкция пыталась использовать нулевую ссылку.
Фактически, исключение является "вероятно" результатом собственного исключения "исключение прав доступа" исключений SEH, которое улавливается средой выполнения и переводится в исключение IL ( "возможно": я не проверял, является ли это case, но это моя догадка о том, что самый эффективный способ JIT кода).
Ответ 5
Не вся информация о вашем коде доступна во время выполнения. Например, локальные имена переменных недоступны. Таким образом, невозможно исключить исключение из сообщения, например, "локальная переменная myObj имеет значение null, но ее член был вызван". Кроме того, во время выполнения много объектов, не написанных пользователем (например, классы, созданные для закрытий/анонимных типов/итераторов и т.д.), Которые также могут быть источником исключений null-ref.
Ответ 6
Если у вас есть символы отладки, вы можете отслеживать строку, вызвавшую исключение. Если это достаточно просто, вы получите прямое значение null
. В противном случае (подумайте о a.Value = b.Do(c.GetX(),d.GetY(z.ToString()));
) вы должны отлаживать свою среду IDE