Object reference not set to an instance of an object как исправить
Перейти к содержимому

Object reference not set to an instance of an object как исправить

  • автор:

Что такое NullReferenceException, и как мне исправить код?

Когда я выполняю некоторый код, выбрасывается исключение NullReferenceException со следующим сообщением:

Object reference not set to an instance of an object.

В экземпляре объекта не задана ссылка на объект.

Что это значит, и как мне исправить код?
Отслеживать
58.2k 7 7 золотых знаков 71 71 серебряный знак 145 145 бронзовых знаков
задан 1 апр 2015 в 10:18
32k 19 19 золотых знаков 79 79 серебряных знаков 105 105 бронзовых знаков

Добавил важный каноничный ответ с английского SO What is a NullReferenceException and how do I fix it?. Теперь можно закрывать большинство вопросов про NRE как дубль, а не ковыряться с каждым отдельным случаем. Всё равно почти всегда одно и то же.

1 апр 2015 в 10:20
Надо ещё про ?. дополнить. Вроде не видно в ответе.
5 июн 2015 в 14:08
@Qwertiy Когда C# 6 релизнется — добавлю.
5 июн 2015 в 14:23
@Discord: Пора! C# 6 вышел.
23 сен 2015 в 20:33
ассоциация: stackoverflow.com/questions/4660142
27 фев 2017 в 17:46

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Причина

Вкратце

Вы пытаетесь воспользоваться чем-то, что равно null (или Nothing в VB.NET). Это означает, что либо вы присвоили это значение, либо вы ничего не присваивали.

Как и любое другое значение, null может передаваться от объекта к объекту, от метода к методу. Если нечто равно null в методе «А», вполне может быть, что метод «В» передал это значение в метод «А».

Остальная часть статьи описывает происходящее в деталях и перечисляет распространённые ошибки, которые могут привести к исключению NullReferenceException .

Более подробно

Если среда выполнения выбрасывает исключение NullReferenceException , то это всегда означает одно: вы пытаетесь воспользоваться ссылкой. И эта ссылка не инициализирована (или была инициализирована, но уже не инициализирована).

Это означает, что ссылка равна null , а вы не сможете вызвать методы через ссылку, равную null . В простейшем случае:

string foo = null; foo.ToUpper(); 

Этот код выбросит исключение NullReferenceException на второй строке, потому что вы не можете вызвать метод ToUpper() у ссылки на string , равной null .

Отладка

Как определить источник ошибки? Кроме изучения, собственно, исключения, которое будет выброшено именно там, где оно произошло, вы можете воспользоваться общими рекомендациями по отладке в Visual Studio: поставьте точки останова в ключевых точках, изучите значения переменных, либо расположив курсор мыши над переменной, либо открыв панели для отладки: Watch, Locals, Autos.

Если вы хотите определить место, где значение ссылки устанавливается или не устанавливается, нажмите правой кнопкой на её имени и выберите «Find All References». Затем вы можете поставить точки останова на каждой найденной строке и запустить приложение в режиме отладки. Каждый раз, когда отладчик остановится на точке останова, вы можете удостовериться, что значение верное.

Следя за ходом выполнения программы, вы придёте к месту, где значение ссылки не должно быть null , и определите, почему не присвоено верное значение.

Примеры

Несколько общих примеров, в которых возникает исключение.

Цепочка

ref1.ref2.ref3.member 

Если ref1 , ref2 или ref3 равно null , вы получите NullReferenceException . Для решения проблемы и определения, что именно равно null , вы можете переписать выражение более простым способом:

var r1 = ref1; var r2 = r1.ref2; var r3 = r2.ref3; r3.member 

Например, в цепочке HttpContext.Current.User.Identity.Name , значение может отсутствовать и у HttpContext.Current , и у User , и у Identity .

Неявно

public class Person < public int Age < get; set; >> public class Book < public Person Author < get; set; >> public class Example < public void Foo() < Book b1 = new Book(); int authorAge = b1.Author.Age; // Свойство Author не было инициализировано // нет Person, у которого можно вычислить Age. >> 

То же верно для вложенных инициализаторов:

Book b1 = new Book < Author = < Age = 45 >>; 

Несмотря на использование ключевого слова new , создаётся только экземпляр класса Book , но экземпляр Person не создаётся, поэтому свойство Author остаётся null .

Массив

int[] numbers = null; int n = numbers[0]; // numbers = null. Нет массива, чтобы получить элемент по индексу 

Элементы массива

Person[] people = new Person[5]; people[0].Age = 20; // people[0] = null. Массив создаётся, но не // инициализируется. Нет Person, у которого можно задать Age. 

Массив массивов

long[][] array = new long[1][]; array[0][0] = 3; // = null, потому что инициализировано только первое измерение. // Сначала выполните array[0] = new long[2]. 

Collection/List/Dictionary

Dictionary agesForNames = null; int age = agesForNames["Bob"]; // agesForNames = null. // Экземпляр словаря не создан. 

LINQ

public class Person < public string Name < get; set; >> var people = new List(); people.Add(null); var names = from p in people select p.Name; string firstName = names.First(); // Исключение бросается здесь, хотя создаётся // строкой выше. p = null, потому что // первый добавленный элемент = null. 

События

public class Demo < public event EventHandler StateChanged; protected virtual void OnStateChanged(EventArgs e) < StateChanged(this, e); // Здесь бросится исключение, если на // событие StateChanged никто не подписался >> 

Неудачное именование переменных

Если бы в коде ниже у локальных переменных и полей были разные имена, вы бы обнаружили, что поле не было инициализировано:

public class Form1 < private Customer customer; private void Form1_Load(object sender, EventArgs e) < Customer customer = new Customer(); customer.Name = "John"; >private void Button_Click(object sender, EventArgs e) < MessageBox.Show(customer.Name); >> 

Можно избежать проблемы, если использовать префикс для полей:

private Customer _customer; 

Цикл жизни страницы ASP.NET

public partial class Issues_Edit : System.Web.UI.Page < protected TestIssue myIssue; protected void Page_Load(object sender, EventArgs e) < if (!IsPostBack) < // Выполняется только на первой загрузке, но не когда нажата кнопка myIssue = new TestIssue(); >> protected void SaveButton_Click(object sender, EventArgs e) < myIssue.Entry = "NullReferenceException здесь!"; >> 

Сессии ASP.NET

// Если сессионная переменная "FirstName" ещё не была задана, // то эта строка бросит NullReferenceException. string firstName = Session["FirstName"].ToString(); 

Пустые вью-модели ASP.NET MVC

Если вы возвращаете пустую модель (или свойство модели) в контроллере, то вью бросит исключение при попытке доступа к ней:

// Controller public class Restaurant:Controller < public ActionResult Search() < return View(); // Модель не задана. >> // Razor view @foreach (var restaurantSearch in Model.RestaurantSearch) // Исключение.

Способы избежать

Явно проверять на null , пропускать код

Если вы ожидаете, что ссылка в некоторых случаях будет равна null , вы можете явно проверить на это значение перед доступом к членам экземпляра:

void PrintName(Person p) < if (p != null) < Console.WriteLine(p.Name); >> 

Явно проверять на null , использовать значение по умолчанию

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

string GetCategory(Book b)

Явно проверять на null , выбрасывать своё исключение

Вы также можете бросать своё исключение, чтобы позже его поймать:

string GetCategory(string bookTitle) < var book = library.FindBook(bookTitle); // Может вернуть null if (book == null) throw new BookNotFoundException(bookTitle); // Ваше исключение return book.Category; >

Использовать Debug.Assert для проверки на null для обнаружения ошибки до бросания исключения

Если во время разработки вы знаете, что метод может, но вообще-то не должен возвращать null , вы можете воспользоваться Debug.Assert для быстрого обнаружения ошибки:

string GetTitle(int knownBookID) < // Вы знаете, что метод не должен возвращать null var book = library.GetBook(knownBookID); // Исключение будет выброшено сейчас, а не в конце метода. Debug.Assert(book != null, "Library didn't return a book for known book ID."); // Остальной код. return book.Title; // Не выбросит NullReferenceException в режиме отладки. >

Однако эта проверка не будет работать в релизной сборке, и вы снова получите NullReferenceException , если book == null .

Использовать GetValueOrDefault() для Nullable типов

DateTime? appointment = null; Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now)); // Отобразит значение по умолчанию, потому что appointment = null. appointment = new DateTime(2022, 10, 20); Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now)); // Отобразит дату, а не значение по умолчанию. 

Использовать оператор ?? (C#) или If() (VB)

Краткая запись для задания значения по умолчанию:

IService CreateService(ILogger log, Int32? frobPowerLevel)

Использовать операторы ?. и ?[ (C# 6+, VB.NET 14+):

Это оператор безопасного доступа к членам, также известный как оператор Элвиса за специфическую форму. Если выражение слева от оператора равно null , то правая часть игнорируется, и результатом считается null . Например:

var title = person.Title.ToUpper(); 

Если свойство Title равно null , то будет брошено исключение, потому что это попытка вызвать метод ToUpper на значении, равном null . В C# 5 и ниже можно добавить проверку:

var title = person.Title == null ? null : person.Title.ToUpper(); 

Теперь вместо бросания исключения переменной title будет присвоено null . В C# 6 был добавлен более короткий синтаксис:

var title = person.Title?.ToUpper(); 

Разумеется, если переменная person может быть равна null , то надо проверять и её. Также можно использовать операторы ?. и ?? вместе, чтобы предоставить значение по умолчанию:

// обычная проверка на null int titleLength = 0; if (title != null) titleLength = title.Length; // совмещаем операторы `?.` и `??` int titleLength = title?.Length ?? 0; 

Если любой член в цепочке может быть null , то можно полностью обезопасить себя (хотя, конечно, архитектуру стоит поставить под сомнение):

int firstCustomerOrderCount = customers?[0]?.Orders?.Count() ?? 0; 

Отслеживать
453 2 2 серебряных знака 17 17 бронзовых знаков
ответ дан 1 апр 2015 в 10:18
32k 19 19 золотых знаков 79 79 серебряных знаков 105 105 бронзовых знаков

Мне кажется, в рекомендациях по предотвращению не хватает вот чего: в большинстве случаев семантика полей — non-nullable. В таких случаях NRE означает ошибку в логике программы: что-то недоинициализировано, объект в неправильном состоянии. В этом случае не проверять на null и игнорировать ошибку (что прячет баг, а не способствует его исправлению), а исправить код, который должен гарантировать, что null не будет.

11 окт 2015 в 11:09

@VladD Есть слишком много случаев, когда null — допустимое значение: ленивая инициализация, отсутствие значения «не задано» у типа и т. п. Не везде получается избавиться от null. Так что рекомендация сводится к «старайтесь не использовать null, если это возможно».

11 окт 2015 в 13:06

Это да, есть случаи, когда null валиден. Тогда, вероятно, первым вопросом должно быть: валиден ли null в этой точке? Если да, нужна проверка на null и адекватная реакция. Если нет, то код верен, а проблема где-то раньше (скорее всего в инициализации).

11 окт 2015 в 17:03
c# 6.0 null propagation: ref1?.ref2?.ref3?.member
29 мая 2017 в 21:10

В дополнение к ответу @Discord @Squidward @Athari @Kyubey, давайте рассмотрим вопрос с другой стороны.

Если у вас в процессе выполнения программы случился NullReferenceException при доступе по какой-то ссылке, вы должны прежде всего задать себе важный вопрос:

а имеет ли право эта ссылка иметь значение null ?

Во многих случаях правильным ответом будет «нет», и значит, исправлять придётся истинную причину ошибки, которая находится в другом месте, и произошла раньше.

Пример: если у вас есть такой класс:

class Car < Engine engine; Driver driver; // . остаток класса >

Так вот, мотор у машины быть обязан в любом случае, всегда. А вот водитель может в принципе и не сидеть в машине.

Поэтому если вы видите, что обращение к engine.HorsePower падает с NullReferenceException , реальная проблема состоит в том, что вы забыли инициализировать engine в конструкторе. Поэтому и исправлять ошибку нужно не в точке, где падает, а в том месте, которое реально должно бы обеспечить ненулевое значение engine .

А вот если вылетает обращение driver.Age , то здесь уже проблема прямо в точке обращения, вам необходимо сначала проверить, что driver != null , а потом уж обращаться.

Таким образом: если ваша ссылка в точке обращения не имеет права иметь значение null , то вы не должны дописывать проверку на null , тем самым «замазывая» ошибку. Вы должны либо ничего не проверять, а исправить в том месте, где ссылка должна быть инициализирована, либо добавить Debug.Assert , либо проверку на null и выброс исключения.

Если же ссылка имеет право быть null -ом, то в этом случае нужно корректно обработать и этот случай.

Важное замечание: Если вашу функцию вызывает «внешний мир», вы не должны рассчитывать, что вашей функции передадут хорошие, правильные аргументы. Даже если вы требуете, чтобы объект, который вам передан, не был null -ом, всё равно вам могут передать неправильный объект. Поэтому для функций, доступных внешним модулям, необходимо проверять аргументы на null сразу же в начале кода, и бросать нужное исключение:

public decimal ComputePrice(Car car) < if (car == null) throw new ArgumentNullException("car"); // . 

Где именно проводить границу между «внутренним» и «внешним» миром, вопрос достаточно нетривиальный. Обычно эта граница есть граница модуля (сборки), или даже той её логической части, которая находится в вашей ответственности. Слишком мелкое дробление ведёт к повторению бессмысленного кода (одна часть программы не доверяет другой и постоянно перепроверяет её). Слишком крупное дробление ведёт к необходимости держать в голове миллионы зависимостей («могу я тут передавать null или нет?»). Пользуйтесь здравым смыслом и личным опытом.

В C# 8 введено, наконец, явное различие между этими двумя случаями. Для тех ссылок, которые могут содержать null , введён специальный синтаксис (в файле должно быть включено #nullable enable (или в проекте enable ):

class Car < Engine engine; // не может быть null Driver? driver; // может быть null // . остаток класса >

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

Почему появляется ошибка «Object reference not set to an instance of an object» при создании проекта в VS 2019?

Всем привет, вот столкнулся с ошибкой, которую ранее не встречал на предыдущих версиях VS -
при создании проекта появляется ошибка "Object reference not set to an instance of an object" (Ссылка на объект не установлена для экземпляра объекта).
При создании как пустого, так и специфичного проекта.
Нагуглить не решение пока не удалось, директории с проектами очищаю, но проблема не исчезает, может, кто-то готов ответить, в чем проблема?
заранее спасибо

  • Вопрос задан более трёх лет назад
  • 1415 просмотров

4 комментария

Простой 4 комментария

Object reference not set to an instance of an object

Ошибка «Object reference not set to an instance of an object» расшифровывается как "Ссылка не указывает на экземпляр объекта".

Данная ошибка означает, что происходит попытка обратиться к null, т.е. к тому, чего не существует. Рассмотрим пример:

public class Program

static string someString;

public static void Main()

При попытке запустить такую программу в среде разработки получаем ошибку

Run-time exception (line 8): Object reference not set to an instance of an object.

[System.NullReferenceException: Object reference not set to an instance of an object.]
at Program.Main() :line 8

В данном случае происходит попытка обратиться к первому символу строки someString, но поскольку там нет никакого значения, а отсутствие значения означает null для string, поэтому происходит ошибка Nullreferenceexception «Object reference not set to an instance of an object».

Попробуем пофиксить ошибку «Ссылка не указывает на экземпляр объекта», присвоим значение строке someString:

public class Program

static string someString;

public static void Main()

Запустим программу и увидим результат, как мы и хотели — получили первый символ строки someString, в данном случае был выведен результат — первая буква s.

Перестала открываться таблица (ошибка «Object reference not set to an instance of an object»)

Если у пользователя или у нескольких пользователей перестала работать таблица, которая раньше работала: таблица не открывается и отображается оповещение об ошибке «Object reference not set to an instance of an object», то скорее всего возник конфликт персональной настройки таблицы и системной настройкой таблицы. Возможно, были внесены какие-либо изменения в системную настройку таблицы, например, удален атрибут, на который был настроен фильтр в персональной конфигурации таблицы.

Решение

Данную проблему получится устранить только путем удаления персональной конфигурации таблицы, где возникла ошибка. Внешний вид таблицы для конечного пользователя, таким образом, будет возвращён к настройкам по умолчанию.

  1. Перейдите в область API, введя после доменного имени сайта «/docs».
  2. Выберите из списка «SystemCoreApi».
  3. Выберите «Ontology», а затем — «GetReferences». В поле запроса введите ИД таблицы и нажмите «Tryitout!». Т.о. вы получите список всех персональных конфигураций указанной таблицы.
  4. Затем нужно найти персональную конфигурацию таблицы, созданную пользователем, у которого возникла ошибка. Выберите «Ontology», а затем — «GetAxioms». В поле запроса введите ИД персональной конфигурации таблицы и нажмите «Tryitout!». Т.о. вы получите информацию по каждой указанной персональной конфигурации таблицы. Повторяйте шаг, пока не найдёте персональную конфигурацию таблицы, созданную определенным пользователем.
  5. После определения персональной конфигурации, которую нужно удалить, выберите «Ontology», а затем — «Remove». В поле запроса введите ИД персональной конфигурации таблицы и нажмите «Tryitout!».

Считаете ли вы эту статью полезной?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *