Во многих случаях получено NullReferenceException
, являющееся одним из исключений, которое вызывает больше всего вопросов. Что это значит NullReferenceException
и как это можно исправить?
Для NullReferenceException
VB.NET см. NullReferenceException: что это такое и как его исправить?
В чем причина?
По сути
Вы пытаетесь использовать какой-то объект, который есть
null
(илиNothing
в VB.NET). Это означает, что либо вы инициализировали его значениемnull
, либо никогда его не инициализировали.null
такое же значение, как и другие, и передается таким же образом. Если у вас естьnull
метод «А», возможно, метод «Б» передалnull
метод «А».Остальная часть этого ответа будет более подробно рассмотрена и покажет распространенные ошибки, которые допускают многие программисты, которые могут привести к ошибке
NullReferenceException
.Более конкретно
Когда среда выполнения запускает его,
NullReferenceException
это всегда означает одно и то же: вы пытаетесь использовать ссылку. Эта ссылка не была инициализирована (или была инициализирована в какой-то момент , но больше не инициализирована).Это означает, что ссылка имеет значение
null
, и члены ссылки не могут быть доступны, если ссылка имеет значениеnull
. Это самый простой случай:Этот код выдаст один
NullReferenceException
во второй строке, так как метод экземпляра не может быть вызванToUpper()
по ссылке,string
указывающей наnull
.Очищение
Как найти источник исключения
NullReferenceException
? Помимо изучения самого исключения, которое будет выброшено именно в том месте, где оно возникло, следует применять общие правила отладки в Visual Studio: стратегически устанавливать точки останова и проверять переменные , либо наводя курсор мыши на их имена, открывая окно (быстрого) просмотра или используя существующие панели отладки, такие как Locals и Auto.Если вы хотите найти, где ссылка назначена или не назначена, щелкните правой кнопкой мыши на ее имени и выберите «Найти все ссылки». Затем вы можете поставить точки останова на все найденные места и снова запустить программу в режиме отладки. Каждый раз, когда отладчик останавливает выполнение в этой точке, вам нужно будет определить, ожидали ли вы, что ссылка в этой точке будет не нулевой, проверив переменную и убедившись, что она указывает на экземпляр, когда это должно быть.
Следуя таким образом ходу программы, вы сможете найти место, где экземпляр не должен быть нулевым, и почему он не был инициализирован должным образом.
Примеры
Некоторые распространенные сценарии, в которых мы можем столкнуться с этим исключением:
общий
Если ref1 или ref2 или ref3 равно
null
, вы получите файлNullReferenceException
. Если вы хотите решить эту задачу, то вам нужно найти, какая именно,null
переписав выражение к его простейшему эквиваленту:Например, в
HttpContext.Current.User.Identity.Name
,HttpContext.Current
может бытьnull
, или свойствоUser
может бытьnull
, или свойствоIdentity
может бытьnull
.экземпляры класса
Когда создается любая переменная ссылочного типа (класса), по умолчанию она инициализируется как
null
.Переменные класса должны быть либо инициализированы, либо присвоены уже инициализированному экземпляру того же класса. Инициализация достигается с помощью ключевого слова
new
.Намекать
Если вы хотите избежать нулевой ссылки дочернего элемента (Person), вы можете инициализировать его в конструкторе родителя (Book).
То же самое относится к инициализаторам вложенных объектов:
Хотя в этом примере используется ключевое слово
new
, оно создает только новый экземплярLibro
, а не новый экземплярPersona
, поэтому свойствоAutor
сохраняетсяnull
.Массивы
Элементы массива
Нерегулярные массивы ( зубчатые массивы )
Коллекции/Списки/Словари
Переменные диапазона (косвенные/отложенные)
События
Имена, которые не соответствуют соглашениям:
Если бы вы назвали поля иначе, чем локальные переменные, вы могли бы заметить, что никогда не инициализировали поле.
Это можно обойти, следуя соглашению о том, что
_
перед именем полей добавляется знак подчеркивания ( ):Жизненный цикл страницы ASP.NET:
Значения сеанса ASP.NET
Модели пустого представления ASP.NET MVC
Если исключение возникает при ссылке на свойство
@Modelo
в представлении ASP.NET MVC, вы должны понимать, чтоModelo
оно инициализируется в вашем методеaction
, когда вы возвращаете (return
) представление. Когда вы возвращаете пустую модель (или свойство модели) из вашего контроллера, возникает исключение, когда представление обращается к нему:Порядок создания элементов управления и событий в WPF
Элементы управления WPF создаются во время вызова
InitializeComponent
в том порядке, в котором они появляются в визуальном дереве. ИсключениеNullReferenceException
может быть вызвано, если элементы управления, созданные ранее с помощью обработчиков событий и т. д. , которые срабатывают во времяInitializeComponent
, элементы управления ссылками, созданные после.Например:
Здесь
comboBox1
он создан раньшеlabel1
. Если событиеcomboBox1_SelectionChanged
пытается сослаться наlabel1
, оно еще не создано.Изменение порядка объявлений в XAML (например, размещение
label1
передcomboBox1
, игнорирование вопросов философии дизайна) решит, по крайней мере,NullReferenceException
в этом случае.бросок с
as
Это не вызовет исключение InvalidCastException, но будет возвращаться
null
при сбое приведения (и приunObjeto
нулевом значении). Так что с ним нужно быть осторожным.LINQ FirstOrDefault() и SingleOrDefault()
Простые версии
First()
иSingle()
выдают исключение, когда ничего нет. В этом случае версии"OrDefault"
возвращают null. Вы должны знать об этом.для каждого
foreach
выдает исключение, когда вы пытаетесь перебрать нулевую коллекцию. Обычно это вызвано неожиданным нулевым результатом метода, возвращающего коллекцию.Более реалистичный пример — выбор узлов из XML-документа. Исключение будет выдано, если узлы не найдены, но первоначальная отладка показывает, что все свойства действительны:
способы избежать этого
Явно проверять
null
и игнорировать нулевые значения.Если вы ожидаете, что ссылка когда-либо может быть нулевой, вы можете спросить, так ли это,
null
прежде чем обращаться к членам экземпляра:Явно проверить
null
и вернуть значение по умолчанию.Вызовы методов, которые, как вы ожидаете, вернут экземпляр, могут возвращать
null
, например, когда искомый объект не найден. В следующих случаях вы можете вернуть значение по умолчанию:Явно проверьте
null
и выдайте пользовательское исключение.Вы также можете сгенерировать пользовательское исключение, чтобы вы могли поймать его в коде, который вызывает метод:
Используйте
Debug.Assert
, если значение никогда не должно бытьnull
, чтобы выявить проблему до того, как будет выдано исключение.Когда вы знаете на этапе разработки, что метод может вернуться,
null
даже если этого никогда не должно произойти, вы можете использоватьDebug.Assert()
, чтобы остановить выполнение программы как можно скорее, когда это произойдет:Эта проверка не будет выполняться для вашей Release Build , что приведет к
NullReferenceException
ее повторному выпускуlibro == null
во время выполнения.Используйте
GetValueOrDefault()
в типах значений «Nullable» ( nullables ), чтобы получить значение по умолчанию, когда они равны нулю.Используйте оператор объединения null :
??
[C#] илиIf()
[VB].Самый короткий способ предоставить значение по умолчанию, когда встречается нуль:
Используйте оператор нулевого условия:
?.
(доступен в C# 6 и VB.NET 14):Этот оператор также называется безопасной навигацией или Элвисом (из-за его формы). Если выражение в левой части оператора равно
null
, правая часть оператора не оценивается, и вместо нее возвращается ,null
. В таком случае:Если у человека нет титула, этот код выдаст исключение, потому что он пытается вызвать
ToUpper
свойство с нулевым значением.В C# 5 и ниже это можно исправить следующим образом:
Теперь переменная
titulo
будетnull
вместо генерирования исключения. C# 6 представляет более короткий синтаксис, который делает то же самое:Результатом этого является то, что переменной
titulo
будет присвоено значение null, и вызовToUpper
никогда не будет выполнен, если онpersona.Titulo
равенnull
.Конечно, вам все равно придется проверять, что
title
это не так,null
или использовать оператор условия null в сочетании с оператором проверки null (??
), чтобы задать значение по умолчанию:Этот ответ является переводом отличного ответа, найденного в английской версии Stack Overflow.
В моем случае у меня был список, инициализированный нулем
Я изменил инициализацию для типа объекта, и это было решено