Уважаемые будущие посетители, ответы на этот вопрос в равной степени относятся к ArgumentNullException . Если ваш вопрос был закрыт как дубликат этого вопроса, и вы испытываете ANE, пожалуйста, следуйте инструкциям в ответах, чтобы отладить и исправить вашу проблему.
@ будет ANE должно происходить только в том случае, если в качестве параметра передается значение NULL. Можете ли вы привести пример, если вопрос ANE закрыт как дубликат этого вопроса?
Джон Сондерс
Это произошло на Мете, но мне нужно было покопаться по ссылке. Но что касается этого комментария, ANE - это просто NRE, но кто-то добавил упреждающую проверку, и вы, по крайней мере, точно знаете, что такое NULL (имя аргумента указано), так что диагностировать немного проще, чем NRE с прямым доступом.
Ответы:
2417
В чем причина?
Нижняя граница
Вы пытаетесь использовать то, что есть null(или Nothingв VB.NET). Это означает, что вы либо установили его null, либо никогда вообще ничего не устанавливали.
Как и все остальное, nullобходит вокруг. Если nullв методе «A», может быть , что метод «В» принят nullк методу «A».
null может иметь разные значения:
Переменные объекта, которые неинициализированы и, следовательно, ни на что не указывают. В этом случае, если вы обращаетесь к свойствам или методам таких объектов, это вызывает NullReferenceException.
Разработчик намеренно использует, nullчтобы указать, что значимых доступных значений нет. Обратите внимание, что C # имеет концепцию типов данных, допускающих значение NULL для переменных (например, таблицы базы данных могут иметь поля NULL), которые можно nullуказывать, чтобы указать, что в них нет сохраненного значения, например, int? a = null;когда знак вопроса указывает, что ему разрешено хранить нуль в переменная a. Вы можете проверить это либо с, if (a.HasValue) {...}либо с if (a==null) {...}. Обнуляемые переменные, как в aэтом примере, позволяют получить доступ к значению a.Valueявно или просто как обычно a. Обратите внимание , что доступ к нему через a.ValueВыдает InvalidOperationExceptionвместо NullReferenceExceptionесли aISnull- вы должны выполнить проверку заранее, т. е. если у вас есть другая переменная, которая может иметь значение nullable, int b;вы должны выполнять назначения, такие как if (a.HasValue) { b = a.Value; }или более короткие if (a != null) { b = a; }.
Остальная часть этой статьи более подробно раскрывает ошибки, которые часто допускают многие программисты, что может привести к NullReferenceException.
Более конкретно
runtimeМетании NullReferenceExceptionвсегда означает то же самое: вы пытаетесь использовать ссылку, и ссылка не инициализируется (или он был когда - то инициализируется, но не больше не инициализирован).
Это означает, что ссылка есть null, и вы не можете получить доступ к членам (таким как методы) через nullссылку. Самый простой случай:
string foo =null;
foo.ToUpper();
Это приведет к NullReferenceExceptionпоявлению второй строки, потому что вы не можете вызвать метод экземпляра ToUpper()для stringссылки, указывающей на null.
Отладка
Как вы находите источник NullReferenceException? Помимо рассмотрения самого исключения, которое будет сгенерировано именно в том месте, где оно происходит, применяются общие правила отладки в Visual Studio: устанавливайте стратегические контрольные точки и проверяйте свои переменные , наведя указатель мыши на их имена, открывая ( Быстро) Наблюдайте за окном или используя различные панели отладки, такие как Locals и Autos.
Если вы хотите узнать, где находится ссылка или нет, щелкните правой кнопкой мыши ее имя и выберите «Найти все ссылки». Затем вы можете установить точку останова в каждом найденном месте и запустить вашу программу с подключенным отладчиком. Каждый раз, когда отладчик прерывает работу на такой точке останова, вам нужно определить, ожидаете ли вы, что ссылка не равна нулю, проверить переменную и убедиться, что она указывает на экземпляр, когда вы этого ожидаете.
Следуя этой программе, вы можете найти место, где экземпляр не должен быть нулевым, и почему он не установлен должным образом.
Примеры
Некоторые распространенные сценарии, в которых может быть выдано исключение:
общий
ref1.ref2.ref3.member
Если ref1 или ref2 или ref3 равны нулю, вы получите NullReferenceException. Если вы хотите решить проблему, то выясните, какая из них равна нулю, переписав выражение в его более простой эквивалент:
В частности, в HttpContext.Current.User.Identity.Name, то HttpContext.Currentможет быть пустым, или Userсвойство может быть пустым, или Identityсвойство может быть пустым.
непрямой
publicclassPerson{publicintAge{get;set;}}publicclassBook{publicPersonAuthor{get;set;}}publicclassExample{publicvoidFoo(){Book b1 =newBook();int authorAge = b1.Author.Age;// You never initialized the Author property.// there is no Person to get an Age from.}}
Если вы хотите избежать нулевой ссылки дочернего (Person), вы можете инициализировать ее в конструкторе родительского (Book) объекта.
Инициализаторы вложенных объектов
То же самое относится и к инициализаторам вложенных объектов:
Book b1 =newBook{Author={Age=45}};
Это переводится как
Book b1 =newBook();
b1.Author.Age=45;
Пока используется newключевое слово, оно создает только новый экземпляр Book, но не новый экземпляр Person, поэтому Authorсвойство остается прежним null.
Вложенная коллекция Initializersведет себя так же:
Person p1 =newPerson{Books={newBook{Title="Title1"},newBook{Title="Title2"},}};
Это переводится как
Person p1 =newPerson();
p1.Books.Add(newBook{Title="Title1"});
p1.Books.Add(newBook{Title="Title2"});
new PersonТолько создает экземпляр Person, но Booksколлекция до сих пор null. InitializerСинтаксис коллекции не создает коллекцию p1.Books, он только переводит в p1.Books.Add(...)операторы.
массив
int[] numbers =null;int n = numbers[0];// numbers is null. There is no array to index.
Элементы массива
Person[] people =newPerson[5];
people[0].Age=20// people[0] is null. The array was allocated but not// initialized. There is no Person to set the Age for.
Зубчатые массивы
long[][] array =newlong[1][];
array[0][0]=3;// is null because only the first dimension is yet initialized.// Use array[0] = new long[2]; first.
Коллекция / Список / Словарь
Dictionary<string,int> agesForNames =null;int age = agesForNames["Bob"];// agesForNames is null.// There is no Dictionary to perform the lookup.
Переменная диапазона (косвенная / отложенная)
publicclassPerson{publicstringName{get;set;}}var people =newList<Person>();
people.Add(null);var names =from p in people select p.Name;string firstName = names.First();// Exception is thrown here, but actually occurs// on the line above. "p" is null because the// first element we added to the list is null.
Мероприятия
publicclassDemo{publiceventEventHandlerStateChanged;protectedvirtualvoidOnStateChanged(EventArgs e){StateChanged(this, e);// Exception is thrown here // if no event handlers have been attached// to StateChanged event}}###Bad Naming Conventions:If you named fields differently from locals, you might have realized that you never initialized the field.
Эту проблему можно решить, следуя соглашению о добавлении префикса к полям с подчеркиванием:
privateCustomer _customer;
Жизненный цикл страницы ASP.NET:
publicpartialclassIssues_Edit:System.Web.UI.Page{protectedTestIssue myIssue;protectedvoidPage_Load(object sender,EventArgs e){if(!IsPostBack){// Only called on first load, not when button clicked
myIssue =newTestIssue();}}protectedvoidSaveButton_Click(object sender,EventArgs e){
myIssue.Entry="NullReferenceException here!";}}
Значения сеанса ASP.NET
// if the "FirstName" session value has not yet been set,// then this line will throw a NullReferenceExceptionstring firstName =Session["FirstName"].ToString();
ASP.NET MVC модели пустого представления
Если исключение возникает при обращении к свойству в @Modelin ASP.NET MVC View, вам нужно понимать, что Modelget задается в вашем методе действия, когда вы returnпросматриваете. Когда вы возвращаете пустую модель (или свойство модели) из вашего контроллера, исключение возникает, когда представления обращаются к нему:
// ControllerpublicclassRestaurant:Controller{publicActionResultSearch(){returnView();// Forgot the provide a Model here.}}// Razor view @foreach(var restaurantSearch inModel.RestaurantSearch)// Throws.{}<p>@Model.somePropertyName</p><!--Alsothrows-->
Порядок и события создания элемента управления WPF
WPFэлементы управления создаются во время вызова InitializeComponentв порядке их появления в визуальном дереве. A NullReferenceExceptionбудет вызываться в случае ранее созданных элементов управления с обработчиками событий и т. Д., Которые срабатывают при InitializeComponentобращении к недавно созданным элементам управления.
Например :
<Grid><!-- Combobox declared first --><ComboBoxName="comboBox1"Margin="10"SelectedIndex="0"SelectionChanged="comboBox1_SelectionChanged"><ComboBoxItemContent="Item 1"/><ComboBoxItemContent="Item 2"/><ComboBoxItemContent="Item 3"/></ComboBox><!-- Label declared later --><LabelName="label1"Content="Label"Margin="10"/></Grid>
Здесь comboBox1создано раньше label1. Если comboBox1_SelectionChangedпопытка сослаться на `label1, он еще не был создан.
Изменение порядка объявлений в XAML(т. Е. Перечисление label1ранее comboBox1, игнорируя вопросы философии дизайна, по крайней мере, решило бы NullReferenceExceptionздесь.
В ролях с as
var myThing = someObject asThing;
Это не бросает, InvalidCastExceptionно возвращает, nullкогда приведение не удается (и когда someObjectсамо по себе является нулевым). Так что знайте об этом.
LINQ FirstOrDefault()иSingleOrDefault()
Простые версии First()и Single()исключения, когда нет ничего. Версии «OrDefault» в этом случае возвращают ноль. Так что знайте об этом.
для каждого
foreachбросает при попытке перебрать нулевую коллекцию. Обычно вызвано неожиданным nullрезультатом от методов, которые возвращают коллекции.
List<int> list =null;foreach(var v in list){}// exception
Более реалистичный пример - выберите узлы из XML-документа. Выдает, если узлы не найдены, но начальная отладка показывает, что все свойства действительны:
foreach(var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
Способов избежать
Явно проверяйте nullи игнорируйте нулевые значения.
Если вы ожидаете, что ссылка иногда будет нулевой, вы можете проверить ее на наличие nullдо доступа к членам экземпляра:
Явно проверьте nullи укажите значение по умолчанию.
Вызов методов, которые вы ожидаете вернуть, может возвращать экземпляр null, например, когда искомый объект не может быть найден. Вы можете вернуть значение по умолчанию, если это так:
Явно проверяйте nullиз вызовов методов и создавайте пользовательское исключение.
Вы также можете выдать пользовательское исключение, только чтобы перехватить его в вызывающем коде:
stringGetCategory(string bookTitle){var book = library.FindBook(bookTitle);// This may return nullif(book ==null)thrownewBookNotFoundException(bookTitle);// Your custom exceptionreturn book.Category;}
Используйте, Debug.Assertесли значение никогда не должно быть null, чтобы поймать проблему раньше, чем возникнет исключение.
Если во время разработки вы знаете, что метод может, но никогда не должен возвращаться null, вы можете использовать его Debug.Assert()для прерывания как можно скорее, когда это произойдет:
stringGetTitle(int knownBookID){// You know this should never return null.var book = library.GetBook(knownBookID);// Exception will occur on the next line instead of at the end of this method.Debug.Assert(book !=null,"Library didn't return a book for known book ID.");// Some other codereturn book.Title;// Will never throw NullReferenceException in Debug mode.}
Используйте GetValueOrDefault()для nullableтипов значений, чтобы обеспечить значение по умолчанию, когда они есть null.
DateTime? appointment =null;Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));// Will display the default value provided (DateTime.Now), because appointment is null.
appointment =newDateTime(2022,10,20);Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));// Will display the appointment date, not the default
Используйте оператор объединения нулей: ??[C #] или If()[VB].
Сокращение для предоставления значения по умолчанию, когда nullвстречается:
IServiceCreateService(ILogger log,Int32? frobPowerLevel){var serviceImpl =newMyService(log ??NullLog.Instance);// Note that the above "GetValueOrDefault()" can also be rewritten to use// the coalesce operator:
serviceImpl.FrobPowerLevel= frobPowerLevel ??5;}
Используйте оператор условия null: ?.или ?[x]для массивов (доступно в C # 6 и VB.NET 14):
Это также иногда называют безопасной навигацией или оператором Элвиса (после его формы). Если выражение в левой части оператора является нулевым, то правая часть не будет вычисляться, и вместо него будет возвращено нулевое значение. Это означает, что такие случаи:
var title = person.Title.ToUpper();
Если у человека нет заголовка, это вызовет исключение, потому что он пытается вызвать ToUpperсвойство с нулевым значением.
В C# 5и ниже, это может быть защищено с:
var title = person.Title==null?null: person.Title.ToUpper();
Теперь переменная заголовка будет иметь значение null вместо исключения. C # 6 вводит более короткий синтаксис для этого:
var title = person.Title?.ToUpper();
Это приведет к тому, что переменная заголовка будет null, и вызов ToUpperне будет выполнен, если person.Titleесть null.
Конечно, вам все равно нужно проверить titleналичие нуля или использовать оператор условия null вместе с оператором объединения нулей ( ??), чтобы задать значение по умолчанию:
// regular null checkint titleLength =0;if(title !=null)
titleLength = title.Length;// If title is null, this would throw NullReferenceException// combining the `?` and the `??` operatorint titleLength = title?.Length??0;
Аналогично, для массивов вы можете использовать ?[i]следующее:
Это сделает следующее: Если значение myIntArrayравно NULL, выражение возвращает значение NULL, и вы можете безопасно проверить его. Если он содержит массив, он будет делать то же самое, что и:
elem = myIntArray[i];и возвращает i<sup>th</sup>элемент.
Использовать нулевой контекст (доступно в C # 8):
Представленные C# 8там нулевые контексты и ссылочные типы, допускающие значение NULL, выполняют статический анализ переменных и выдают предупреждение компилятору, если значение может быть потенциально нулевым или для него установлено значение NULL. Обнуляемые ссылочные типы позволяют типам быть явно пустыми.
Обнуляемый контекст аннотации и обнуляемый контекст предупреждения могут быть установлены для проекта с использованием Nullableэлемента в вашем csprojфайле. Этот элемент настраивает, как компилятор интерпретирует обнуляемость типов и какие предупреждения генерируются. Допустимые настройки:
enable: контекст аннулируемой аннотации включен. Обнуляемый контекст предупреждения включен. Переменные ссылочного типа, например строковые, не обнуляются. Все предупреждения об обнуляемости включены.
отключить: контекст аннулируемой аннотации отключен. Обнуляемый контекст предупреждения отключен. Переменные ссылочного типа не обращают внимания, как и более ранние версии C #. Все предупреждения об обнуляемости отключены.
safeonly: контекст аннулируемых аннотаций включен. Обнуляемый контекст предупреждения безопасен. Переменные ссылочного типа не обнуляются. Все предупреждения об опасности безопасности включены.
Предупреждения: контекст аннулируемой аннотации отключен. Обнуляемый контекст предупреждения включен. Переменные ссылочного типа не обращают внимания. Все предупреждения об обнуляемости включены.
safeonlywarnings: контекст аннулируемой аннотации отключен. Обнуляемый контекст предупреждения безопасен. Переменные ссылочного типа не обращают внимания. Все предупреждения об опасности безопасности включены.
Обнуляемый ссылочный тип отмечается с использованием того же синтаксиса, что и типы значений, допускающие обнуляемое значение: a ?добавляется к типу переменной.
Специальные методы отладки и исправления нулевых разыменований в итераторах
C#поддерживает "блоки итераторов" (называемые "генераторами" в некоторых других популярных языках). Исключения нулевого разыменования могут быть особенно сложными для отладки в блоках итераторов из-за отложенного выполнения:
publicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){for(int i =0; i < count;++i)yieldreturn f.MakeFrob();}...FrobFactory factory = whatever;IEnumerable<Frobs> frobs =GetFrobs();...foreach(Frob frob in frobs){...}
Если whateverрезультаты в nullто MakeFrobкинет. Теперь вы можете подумать, что правильно сделать следующее:
// DON'T DO THISpublicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){if(f ==null)thrownewArgumentNullException("f","factory must not be null");for(int i =0; i < count;++i)yieldreturn f.MakeFrob();}
Почему это не так? Поскольку блок итератора фактически не выполняется до foreach! Вызов GetFrobsпросто возвращает объект, который при повторении запускает блок итератора.
Путем написания нулевой проверки, подобной этой, вы предотвращаете разыменование нулевого значения, но перемещаете исключение нулевого аргумента в точку итерации , а не в точку вызова , и это очень сбивает с толку при отладке .
Правильное исправление:
// DO THISpublicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){// No yields in a public method that throws!if(f ==null)thrownewArgumentNullException("f","factory must not be null");returnGetFrobsForReal(f, count);}privateIEnumerable<Frob>GetFrobsForReal(FrobFactory f,int count){// Yields in a private methodDebug.Assert(f !=null);for(int i =0; i < count;++i)yieldreturn f.MakeFrob();}
То есть создайте приватный вспомогательный метод, который имеет логику блока итератора, и метод публичной поверхности, который выполняет нулевую проверку и возвращает итератор. Теперь, когда GetFrobsвызывается, проверка на ноль происходит немедленно, а затем GetFrobsForRealвыполняется, когда последовательность повторяется.
Если вы изучите источник ссылки LINQна Объекты, вы увидите, что эта техника используется повсеместно. Это немного более неуклюже, чтобы написать, но это делает отладку ошибок недействительности намного легче. Оптимизируйте свой код для удобства звонящего, а не для удобства автора .
Примечание о нулевых разыменованиях в небезопасном коде
C#имеет «небезопасный» режим, который, как следует из названия, чрезвычайно опасен, поскольку обычные механизмы безопасности, которые обеспечивают безопасность памяти и безопасность типов, не применяются. Вы не должны писать небезопасный код, если у вас нет глубокого и глубокого понимания того, как работает память .
В небезопасном режиме вы должны знать о двух важных фактах:
разыменование нулевого указателя приводит к тому же исключению, что и разыменование нулевой ссылки
разыменование недопустимого ненулевого указателя может вызвать это исключение при некоторых обстоятельствах
Чтобы понять, почему это так, это помогает понять, как .NET в первую очередь создает исключения с нулевым разыменованием. (Эти сведения относятся к .NET, работающему в Windows; другие операционные системы используют аналогичные механизмы.)
Память виртуализирована в Windows; каждый процесс получает пространство виртуальной памяти из множества «страниц» памяти, которые отслеживаются операционной системой. На каждой странице памяти установлены флаги, которые определяют, как ее можно использовать: чтение, запись, выполнение и т. Д. Самая нижняя страница помечена как «выдает ошибку, если когда-либо используется каким-либо образом».
И нулевой указатель, и нулевая ссылка в нем C#внутренне представлены как нулевое число, и поэтому любая попытка разыменовать его в соответствующее хранилище памяти приводит к ошибке операционной системы. Затем среда выполнения .NET обнаруживает эту ошибку и превращает ее в исключение нулевой разыменования.
Вот почему разыменование как нулевого указателя, так и нулевой ссылки приводит к одному и тому же исключению.
Как насчет второго пункта? Разыменование любого недопустимого указателя, который попадает на нижнюю страницу виртуальной памяти, вызывает ту же ошибку операционной системы и, следовательно, то же исключение.
Почему это имеет смысл? Хорошо, предположим, что у нас есть структура, содержащая два целых числа, и неуправляемый указатель, равный нулю. Если мы попытаемся разыменовать второй тип int в структуре, CLRон не будет пытаться получить доступ к хранилищу в нулевом местоположении; он получит доступ к хранилищу в расположении четыре. Но логически это нулевая разыменование, потому что мы получаем по этому адресу через нуль.
Если вы работаете с небезопасным кодом и получаете исключение нулевой разыменования, просто имейте в виду, что указатель-нарушитель не обязательно должен быть нулевым. Это может быть любое место на самой нижней странице, и будет сделано это исключение.
Может быть, это глупый комментарий, но первым и лучшим способом избежать этой проблемы будет инициализация объекта? Для меня, если эта ошибка происходит, это обычно потому, что я забыл инициализировать что-то вроде элемента массива. Я думаю, что гораздо реже определять объект как нулевой, а затем ссылаться на него. Может быть, дать способ решить каждую проблему, смежную с описанием. Все еще хороший пост.
JPK
30
Что если нет объекта, а скорее возвращаемое значение из метода или свойства?
Джон Сондерс
6
Пример книги / автора немного странный .... Как это вообще компилируется? Как работает intellisense? Что это я не очень хорошо с computar ...
5
@Will: мое последнее редактирование помогает? Если нет, то, пожалуйста, будьте более явными в том, что вы видите в качестве проблемы.
Джон Сондерс
6
@JohnSaunders О, нет, извините, я имел в виду версию инициализатора объекта. new Book { Author = { Age = 45 } };Как внутренняя инициализация даже ... Я не могу представить ситуацию, когда внутренний init будет работать, но он компилируется и работает intellisense ... Разве что для структур?
311
Исключение NullReference - Visual Basic
NullReference ExceptionДля Visual Basic ничем не отличается от такового в C # . В конце концов, они оба сообщают об одном и том же исключении, определенном в .NET Framework, которое они оба используют. Причины, уникальные для Visual Basic, встречаются редко (возможно, только одна).
В этом ответе будут использоваться термины, синтаксис и контекст Visual Basic. Используемые примеры взяты из большого количества прошлых вопросов о переполнении стека. Это максимально уместность, используя виды ситуаций , часто видели в сообщениях. Немного больше объяснений также предоставляется тем, кому это может понадобиться. Пример, похожий на ваш, очень вероятно, приведен здесь.
Замечания:
Это основано на концепции: нет кода для вставки в ваш проект. Он предназначен для того, чтобы помочь вам понять, что вызывает NullReferenceException(NRE), как его найти, как его исправить и как его избежать. NRE может быть вызвано многими способами, так что вряд ли это будет ваша единственная встреча.
Примеры (из сообщений Stack Overflow) не всегда показывают лучший способ сделать что-либо в первую очередь.
Как правило, самое простое средство используется.
Основное значение
Сообщение «Объект не установлен в экземпляр объекта» означает, что вы пытаетесь использовать объект, который не был инициализирован. Это сводится к одному из них:
Ваш код объявил переменный объект, но это не инициализировать его (создать экземпляр или « Instantiate » это)
То, что ваш код предполагал инициализировать объект, не
Возможно, другой код преждевременно лишил законной силы объект, все еще используемый
В поисках причины
Так как проблема заключается в ссылке на объект Nothing, ответ заключается в том, чтобы изучить их, чтобы выяснить, какая из них. Затем определите, почему он не инициализирован. Наведите курсор на различные переменные, и Visual Studio (VS) покажет их значения - виновник будет Nothing.
Вам также следует удалить все блоки Try / Catch из соответствующего кода, особенно те, в которых нет ничего в блоке Catch. Это приведет к сбою вашего кода при попытке использовать объект, который есть Nothing. Это то, что вы хотите, потому что он будет определять точное местоположение проблемы и позволит вам определить объект, вызывающий ее.
А MsgBoxв улове, который отображает Error while..., мало поможет. Этот метод также приводит к очень плохим вопросам переполнения стека, потому что вы не можете описать фактическое исключение, задействованный объект или даже строку кода, где это происходит.
Вы также можете использовать Locals Window( Debug -> Windows -> Locals ) для проверки ваших объектов.
После того, как вы знаете, в чем и где проблема, ее обычно довольно легко исправить и быстрее, чем опубликовать новый вопрос.
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Проблема в том, что Dimне создает объект CashRegister ; он объявляет только переменную с именем regэтого типа. Объявление переменной объекта и создание экземпляра - это две разные вещи.
средство
NewОператор часто может быть использован для создания экземпляра при объявлении его:
Dim reg AsNew CashRegister ' [New] creates instance, invokes the constructor' Longer, more explicit form:Dim reg As CashRegister =New CashRegister
Примечание. Не используйте Dimснова в процедуре, включая конструктор ( Sub New):
Private reg As CashRegister
'...PublicSubNew()'...Dim reg AsNew CashRegister
EndSub
Это создаст локальную переменную, regкоторая существует только в этом контексте (подпункте). regПеременной с уровнем модуля , Scopeкоторый вы будете использовать в любом другом месте остается Nothing.
Отсутствие Newоператора - причина № 1,NullReference Exceptions замеченная в рассмотренных вопросах переполнения стека.
Visual Basic пытается прояснить процесс многократно, используя New: Использование Newоператора создает новый объект и вызывает Sub New- конструктор - где ваш объект может выполнить любую другую инициализацию.
Чтобы было понятно, Dim(или Private) объявляет только переменную и ее Type. Объем переменной - существует ли она для всего модуля / класса или является локальным для процедуры - определяется , где она объявлена. Private | Friend | Publicопределяет уровень доступа, а не Scope .
Этот массив только объявлен, но не создан. Существует несколько способов инициализации массива:
Private arr asString()=NewString(10){}' orPrivate arr()AsString=NewString(10){}' For a local array (in a procedure) and using 'Option Infer':Dim arr =NewString(10){}
Примечание: Начиная с VS 2010, при инициализации локальный массив с использованием буквальным и Option Infer, то As <Type>и Newэлементы не являются обязательными:
Dim myDbl AsDouble()={1.5,2,9.9,18,3.14}Dim myDbl =NewDouble(){1.5,2,9.9,18,3.14}Dim myDbl()={1.5,2,9.9,18,3.14}
Тип данных и размер массива выводятся из назначаемых данных. Объявления уровня класса / модуля все еще требуют As <Type>с Option Strict:
Private myDoubles AsDouble()={1.5,2,9.9,18,3.14}
Пример: массив объектов класса
Dim arrFoo(5)As Foo
For i AsInteger=0To arrFoo.Count -1
arrFoo(i).Bar = i *10' ExceptionNext
Массив был создан, но Fooобъекты в нем нет.
средство
For i AsInteger=0To arrFoo.Count -1
arrFoo(i)=New Foo()' Create Foo instance
arrFoo(i).Bar = i *10Next
С помощью a List(Of T)будет довольно сложно иметь элемент без действительного объекта:
Dim FooList AsNew List(Of Foo)' List created, but it is emptyDim f As Foo ' Temporary variable for the loopFor i AsInteger=0To5
f =New Foo()' Foo instance created
f.Bar = i *10
FooList.Add(f)' Foo object added to listNext
Коллекции .NET (из которых существует множество разновидностей - списки, словарь и т. Д.) Также должны быть созданы или созданы.
Private myList As List(Of String)..
myList.Add("ziggy")' NullReference
Вы получаете то же исключение по той же причине - myListбыло объявлено, но экземпляр не создан. Средство защиты такое же:
myList =New List(Of String)' Or create an instance when declared:Private myList AsNew List(Of String)
Обычный недосмотр - это класс, который использует коллекцию Type:
PublicClass Foo
Private barList As List(Of Bar)FriendFunction BarCount AsIntegerReturn barList.Count
EndFunctionFriendSub AddItem(newBar As Bar)If barList.Contains(newBar)=FalseThen
barList.Add(newBar)EndIfEndFunction
Любая процедура приведет к NRE, потому что barListона только объявлена, а не создана. Создание экземпляра Fooне будет также создавать экземпляр внутреннего barList. Возможно, это было сделано в конструкторе:
PublicSubNew' Constructor' Stuff to do when a new Foo is created...
barList =New List(Of Bar)EndSub
Как и раньше, это неверно:
PublicSubNew()' Creates another barList local to this procedureDim barList AsNew List(Of Bar)EndSub
Для получения дополнительной информации см. List(Of T)Класс .
Объекты провайдера данных
Работа с базами данных представляет много возможностей для NullReference , потому что может быть много объектов ( Command, Connection, Transaction, Dataset, DataTable, DataRows....) в использовании сразу. Примечание: не имеет значения, какой поставщик данных вы используете - MySQL, SQL Server, OleDB и т. Д. - концепции одинаковы.
Пример 1
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows AsInteger
con.Open()Dim sql ="SELECT * FROM tblfoobar_List"
da =New OleDbDataAdapter(sql, con)
da.Fill(ds,"foobar")
con.Close()
MaxRows = ds.Tables("foobar").Rows.Count ' Error
Как и прежде, dsобъект Dataset был объявлен, но экземпляр не был создан. DataAdapterЗаполнит существующий DataSet, не создать. В этом случае, поскольку dsэто локальная переменная, IDE предупреждает вас о том, что это может произойти:
Когда объявлено как переменная уровня модуля / класса, как, кажется, имеет место con, компилятор не может знать, был ли объект создан вышестоящей процедурой. Не игнорируйте предупреждения.
Опечатка проблема здесь: Employeesпротив Employee. Имя DataTableсотрудника не было создано, поэтому NullReferenceExceptionрезультаты пытаются получить к нему доступ. Другая потенциальная проблема заключается в предположении, что это Itemsможет быть не так, когда SQL включает предложение WHERE.
средство
Поскольку при этом используется одна таблица, использование Tables(0)позволит избежать орфографических ошибок. Экспертиза Rows.Countтакже может помочь:
If ds.Tables(0).Rows.Count >0Then
txtID.Text = ds.Tables(0).Rows(0).Item(1)
txtID.Name = ds.Tables(0).Rows(0).Item(2)EndIf
Fillэто функция, возвращающая число Rowsзатронутых, которая также может быть проверена:
If da.Fill(ds,"Employees")>0Then...
Пример 3
Dim da AsNew OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)Dim ds AsNew DataSet
da.Fill(ds)If ds.Tables("TICKET_RESERVATION").Rows.Count >0Then
DataAdapterОбеспечит , TableNamesкак показано в предыдущем примере, но не обрабатывает имена из SQL или базы данных таблицы. В результате ds.Tables("TICKET_RESERVATION")ссылается на несуществующую таблицу.
Устранение такой же, ссылки на таблицу с помощью индекса:
Код только тестирует и Itemsто и другое, myFooи Barможет также быть Nothing. Средство защиты состоит в том, чтобы проверять всю цепочку или путь объектов по одному:
AndAlsoявляется важным. Последующие тесты не будут выполнены, как только Falseбудет встречено первое условие. Это позволяет коду безопасно «углубляться» в объект (ы) по одному «уровню» за раз, оценивая myFoo.Barтолько после того, как (и если) myFooбудет определено, что он действителен. Цепочки объектов или пути могут быть довольно длинными при кодировании сложных объектов:
Здесь myWebBrowserили Documentможет быть Nothing или formfld1элемент может не существовать.
UI Controls
Dim cmd5 AsNew SqlCommand("select Cartons, Pieces, Foobar " _
&"FROM Invoice where invoice_no = '"& _
Me.ComboBox5.SelectedItem.ToString.Trim &"' And category = '"& _
Me.ListBox1.SelectedItem.ToString.Trim &"' And item_name = '"& _
Me.ComboBox2.SelectedValue.ToString.Trim &"' And expiry_date = '"& _
Me.expiry.Text &"'", con)
Среди прочего, этот код не предполагает, что пользователь, возможно, не выбрал что-то в одном или нескольких элементах управления пользовательского интерфейса. ListBox1.SelectedItemвполне может быть Nothing, поэтому ListBox1.SelectedItem.ToStringприведет к NRE.
средство
Проверьте данные перед их использованием (также используйте Option Strictи параметры SQL):
Dim expiry As DateTime ' for text date validationIf(ComboBox5.SelectedItems.Count >0)AndAlso(ListBox1.SelectedItems.Count >0)AndAlso(ComboBox2.SelectedItems.Count >0)AndAlso(DateTime.TryParse(expiry.Text, expiry)Then'... do stuffElse
MessageBox.Show(...error message...)EndIf
Кроме того, вы можете использовать (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Visual Basic Forms
PublicClass Form1
Private NameBoxes =New TextBox(5){Controls("TextBox1"), _
Controls("TextBox2"), Controls("TextBox3"), _
Controls("TextBox4"), Controls("TextBox5"), _
Controls("TextBox6")}' same thing in a different format:Private boxList AsNew List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}' Immediate NRE:Private somevar AsString=Me.Controls("TextBox1").Text
Это довольно распространенный способ получить NRE. В C #, в зависимости от того, как это закодировано, IDE сообщит, что Controlsне существует в текущем контексте, или «не может ссылаться на нестатический член». Так что, в некоторой степени, это ситуация только для VB. Это также сложно, потому что это может привести к каскаду сбоев.
Массивы и коллекции не могут быть инициализированы таким образом. Этот код инициализации будет запущен до того, как конструктор создаст Formили Controls. В результате:
Списки и Коллекция будут просто пустыми
Массив будет содержать пять элементов Nothing
somevarНазначение приведет к немедленному ЯРДУ , потому что ничего не имеет .Textсвойства
Ссылка на элементы массива позже приведет к NRE. Если вы сделаете это Form_Loadиз-за странной ошибки, IDE может не сообщить об исключении, когда это произойдет. Исключение появится позже, когда ваш код попытается использовать массив. Это «тихое исключение» подробно описано в этом посте . Для наших целей ключевым моментом является то, что когда происходит что-то катастрофическое во время создания формы ( Sub Newили Form Loadсобытия), исключения могут остаться незамеченными, код выходит из процедуры и просто отображает форму.
Поскольку никакой другой код в вашем Sub Newили Form Loadсобытии не будет выполняться после NRE, многие другие вещи можно оставить неинициализированными.
Sub Form_Load(..._
'...Dim name AsString= NameBoxes(2).Text ' NRE' ...' More code (which will likely not be executed)' ...EndSub
Обратите внимание, что это относится ко всем без исключения ссылкам на элементы управления и компонентов, что делает их недопустимыми, если они:
Любопытно , что VB не дает предупреждение, а средство для объявить контейнеры на уровне формы, но инициализировать их в обработчик события загрузки формы , когда элементы управления делают существует. Это можно сделать, Sub Newесли ваш код находится после InitializeComponentвызова:
' Module level declarationPrivate NameBoxes as TextBox()Private studentName AsString' Form Load, Form Shown or Sub New:'' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes =New TextBox(){Me.Controls("TextBox1"),Me.Controls("TestBox2"),...)
studentName = TextBox32.Text ' For simple control references
Код массива еще может быть не в лесу. Любые элементы управления, которые находятся в элементе управления контейнера (например, GroupBoxили Panel), не будут найдены в Me.Controls; они будут в коллекции Controls этой Panel или GroupBox. Также не будет возвращен элемент управления, если имя элемента управления написано с ошибкой ( "TeStBox2"). В таких случаях Nothingони снова будут храниться в этих элементах массива, и при попытке ссылки на него будет получено NRE.
Теперь их легко найти, когда вы знаете, что ищете:
"Button2" находится на Panel
средство
Вместо косвенных ссылок по имени с использованием Controlsколлекции формы используйте контрольную ссылку:
' DeclarationPrivate NameBoxes As TextBox()' Initialization - simple and easy to read, hard to botch:
NameBoxes =New TextBox(){TextBox1, TextBox2,...)' Initialize a List
NamesList =New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})' or
NamesList =New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})
Функция ничего не возвращает
Private bars AsNew List(Of Bars)' Declared and createdPublicFunction BarList()As List(Of Bars)
bars.Clear
If someCondition ThenFor n AsInteger=0to someValue
bars.Add(GetBar(n))Next n
ElseExitFunctionEndIfReturn bars
EndFunction
Это тот случай, когда IDE предупредит вас, что « не все пути возвращают значение и NullReferenceExceptionможет привести к результату ». Вы можете подавить предупреждение, заменив Exit Functionс Return Nothing, но это не решает проблему. Все, что пытается использовать возвращение, когда someCondition = Falseприведет к NRE:
bList = myFoo.BarList()ForEach b As Bar in bList ' EXCEPTION...
средство
Заменить Exit Functionв функции на Return bList. Возврат пустогоList не означает возвращение Nothing. Если есть вероятность, что возвращенный объект может быть Nothing, протестируйте перед его использованием:
Плохо реализованный Try / Catch может скрыть, где проблема, и привести к новым:
Dim dr As SqlDataReader
TryDim lnk As LinkButton = TryCast(sender, LinkButton)Dim gr As GridViewRow =DirectCast(lnk.NamingContainer, GridViewRow)Dim eid AsString= GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username")= eid
sqlQry ="select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username='"& eid &"'"If connection.State <> ConnectionState.Open Then
connection.Open()EndIf
command =New SqlCommand(sqlQry, connection)'More code fooing and barring
dr = command.ExecuteReader()If dr.Read()Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))...EndIf
mpe.Show()CatchFinally
command.Dispose()
dr.Close()' <-- NRE
connection.Close()EndTry
Это случай, когда объект создается не так, как ожидалось, но также демонстрирует полезность счетчика пустого Catch.
В SQL есть дополнительная запятая (после 'mailaddress'), что приводит к исключению в .ExecuteReader. После того, Catchкак ничего не делает, Finallyпытается выполнить очистку, но, поскольку вы не можете Closeнулевой DataReaderобъект, совершенно новый NullReferenceExceptionрезультат.
Пустой Catchблок - игровая площадка дьявола. Этот ОП был сбит с толку, почему он получил NRE в Finallyблоке. В других ситуациях пустое состояние Catchможет привести к тому, что что-то еще ниже по течению станет бесполезным, и вы потратите время на поиск неправильных вещей в неподходящем месте для решения проблемы. (Описанное выше «тихое исключение» обеспечивает ту же развлекательную ценность.)
средство
Не используйте пустые блоки Try / Catch - позвольте коду аварийно завершить работу, чтобы вы могли a) определить причину b) определить местоположение и c) применить надлежащее решение. Блоки Try / Catch не предназначены для сокрытия исключений от лица, обладающего уникальной квалификацией для их устранения - разработчика.
DBNull не то же самое, что Nothing
ForEach row As DataGridViewRow In dgvPlanning.Rows
IfNot IsDBNull(row.Cells(0).Value)Then...
IsDBNullФункция используется для проверки , если значение равно System.DBNull: Из MSDN:
Значение System.DBNull указывает, что объект представляет отсутствующие или несуществующие данные. DBNull отличается от Nothing, что указывает на то, что переменная еще не инициализирована.
средство
If row.Cells(0) IsNot NothingThen...
Как и раньше, вы можете проверить на Ничто, а затем для конкретного значения:
Dim getFoo =(From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
IfNot IsDBNull(getFoo)ThenIf IsDBNull(getFoo.user_id)Then
txtFirst.Text = getFoo.first_name
Else...
FirstOrDefaultвозвращает первый элемент или значение по умолчанию, которое предназначено Nothingдля ссылочных типов и никогда DBNull:
If getFoo IsNot NothingThen...
управления
Dim chk As CheckBox
chk =CType(Me.Controls(chkName), CheckBox)If chk.Checked ThenReturn chk
EndIf
Если CheckBoxс chkNameне может быть найдено (или существует в GroupBox), то chkбудет Nothing, и попытка ссылки на какое-либо свойство приведет к исключению.
средство
If(chk IsNot Nothing)AndAlso(chk.Checked)Then...
DataGridView
У DGV есть несколько причуд, периодически замечаемых:
Если dgvBooksимеет AutoGenerateColumns = True, он будет создавать столбцы, но он не называет их, поэтому приведенный выше код завершается ошибкой, когда он ссылается на них по имени.
средство
Назовите столбцы вручную или используйте указатель по индексу:
Когда у вас DataGridViewесть AllowUserToAddRowsas True(по умолчанию), Cellsв пустой / новой строке внизу все будет содержать Nothing. Большинство попыток использовать содержимое (например, ToString) приведет к NRE.
средство
Используйте For/Eachцикл и протестируйте IsNewRowсвойство, чтобы определить, последняя ли это строка. Это работает независимо от того AllowUserToAddRows, верно это или нет:
ForEach r As DataGridViewRow in myDGV.Rows
If r.IsNewRow =FalseThen' ok to use this row
Если вы используете For nцикл, изменять количество строк или использовать , Exit Forкогда IsNewRowэто верно.
My.Settings (StringCollection)
При определенных обстоятельствах попытка использовать элемент из My.Settingsкоторого StringCollectionможет привести к NullReference при первом его использовании. Решение то же самое, но не так очевидно. Рассматривать:
My.Settings.FooBars.Add("ziggy")' foobars is a string collection
Поскольку VB управляет настройками для вас, разумно ожидать, что он инициализирует коллекцию. Это произойдет, но только если вы ранее добавили начальную запись в коллекцию (в редакторе настроек). Поскольку коллекция (по-видимому) инициализируется при добавлении элемента, она остается, Nothingкогда в редакторе настроек нет элементов для добавления.
средство
Инициализируйте коллекцию настроек в Loadобработчике событий формы, если / когда это необходимо:
If My.Settings.FooBars IsNothingThen
My.Settings.FooBars =New System.Collections.Specialized.StringCollection
EndIf
Как правило, Settingsколлекция должна быть инициализирована только при первом запуске приложения. Альтернативное решение - добавить начальное значение в вашу коллекцию в Project -> Settings | FooBars , сохраните проект, затем удалите поддельное значение.
Ключевые моменты
Вы, наверное, забыли Newоператора.
или
То, что вы предполагали, будет работать безупречно, чтобы вернуть инициализированный объект в ваш код, не так.
Не игнорируйте предупреждения компилятора (всегда) и используйте Option Strict On(всегда).
Другой сценарий - когда вы приводите нулевой объект в тип значения . Например, код ниже:
object o =null;DateTime d =(DateTime)o;
Это бросит NullReferenceExceptionна бросок. Это кажется вполне очевидным в приведенном выше примере, но это может произойти в более сложных запоздалых сценариях, когда нулевой объект был возвращен из некоторого кода, который вам не принадлежит, и приведение, например, генерируется некоторой автоматической системой.
Одним из примеров этого является этот простой фрагмент привязки ASP.NET с элементом управления Calendar:
Здесь, SelectedDateна самом деле, это свойство - DateTimeтипа - типа CalendarWeb Control, и привязка может совершенно вернуть что-то нулевое. Неявный ASP.NET Generator создаст кусок кода, который будет эквивалентен приведенному выше коду. И это вызовет NullReferenceExceptionдовольно трудную задачу, потому что он лежит в сгенерированном ASP.NET коде, который прекрасно компилируется ...
Это выдаст ошибку, потому что, хотя я объявил переменную " connection", она ни на что не указана. Когда я пытаюсь вызвать участника " Open", нет ссылки для его разрешения, и он выдаст ошибку.
Чтобы избежать этой ошибки:
Всегда инициализируйте ваши объекты, прежде чем пытаться что-либо с ними делать.
Если вы не уверены, является ли объект нулевым, проверьте его с помощью object == null.
Инструмент JetBrains Resharper будет идентифицировать каждое место в вашем коде, в котором может быть ошибка нулевой ссылки, что позволяет вам поставить нулевую проверку. Эта ошибка - источник ошибок номер один, ИМХО.
Инструмент JetBrains Resharper определит каждое место в вашем коде, в котором может быть ошибка нулевой ссылки. Это неверно У меня есть решение без этого обнаружения, но код иногда приводит к исключению. Я подозреваю, что это иногда необнаружимо - по крайней мере ими, - когда задействована многопоточность, но я не могу комментировать дальше, потому что я еще не определил местоположение моей ошибки.
Дж Рив
Но как решить эту проблему, когда исключение NullReferenceException входит в usign HttpContext.Current.Responce.Clear (). Это не решается ни одним из вышеуказанных решений. потому что при создании своего объекта объекта HttpContext то ошибка приходит «разрешение перегрузки не удалось , поскольку не доступно„Новые“не принимает это число аргументов.
Солнечный SANDEEP
158
Это означает, что ваш код использовал переменную ссылки на объект, для которой было установлено значение null (то есть он не ссылался на фактический экземпляр объекта).
Чтобы предотвратить ошибку, объекты, которые могут иметь значение NULL, должны быть проверены на NULL перед использованием.
if(myvar !=null){// Go ahead and use myvar
myvar.property=...}else{// Whoops! myvar is null and cannot be used without first// assigning it to an instance reference// Attempting to use myvar here will result in NullReferenceException}
Имейте в виду, что независимо от сценария, причина всегда одинакова в .NET:
Вы пытаетесь использовать ссылочную переменную со значением Nothing/ null. Когда значение равно Nothing/ nullдля ссылочной переменной, это означает, что оно фактически не содержит ссылку на экземпляр любого объекта, который существует в куче.
Вы либо никогда не присваивали что-либо переменной, никогда не создавали экземпляр значения, назначенного переменной, либо устанавливали переменную равной Nothing/ nullвручную, либо вызывали функцию, которая устанавливает переменную для Nothing/ nullдля вас.
Пример этого исключения: Когда вы пытаетесь что-то проверить, это пустое значение.
Например:
string testString =null;//Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)if(testString.Length==0)// Throws a nullreferenceexception{//Do something}
Среда выполнения .NET генерирует исключение NullReferenceException при попытке выполнить действие с чем-то, что не было создано, например с кодом выше.
По сравнению с ArgumentNullException, который обычно генерируется как защитная мера, если метод ожидает, что то, что ему передается, не равно нулю.
C # 8.0 вводит пустые ссылочные типы и ненулевые ссылочные типы . Поэтому необходимо проверять только обнуляемые ссылочные типы, чтобы избежать исключения NullReferenceException .
Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, оно выдаст исключение NullReferenceException .
Пример:
Person p =null;
p.Name="Harry";// NullReferenceException occurs here.
Вы можете просто избежать этого, проверив, не является ли переменная нулевой:
Person p =null;if(p!=null){
p.Name="Harry";// Not going to run to this point}
Чтобы полностью понять, почему выбрасывается исключение NullReferenceException, важно знать разницу между типами значений и [ссылочными типами] [3].
Итак, если вы имеете дело с типами значений , NullReferenceExceptions не может возникнуть. Хотя при работе с ссылочными типами нужно соблюдать бдительность !
Только ссылочные типы, как следует из названия, могут содержать ссылки или указывать буквально на ничто (или «ноль»). В то время как типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
динамический
объект
строка
Типы значений (вы можете просто игнорировать эти):
-1: поскольку вопрос «Что такое исключение NullReferenceException», типы значений не имеют значения.
Джон Сондерс
21
@ Джон Сондерс: я не согласен. Как разработчику программного обеспечения очень важно уметь различать значения и ссылочные типы. иначе люди в конечном итоге проверят, являются ли целые числа нулевыми.
Фабиан Биглер
5
Правда, просто не в контексте этого вопроса.
Джон Сондерс
4
Спасибо за подсказку. Я немного улучшил его и добавил пример вверху. Я все еще думаю, что упоминание Reference & Value Types полезно.
Фабиан Биглер
5
Я думаю, что вы не добавили ничего, чего не было в других ответах, так как вопрос предполагает тип ссылки.
Джон Сондерс
78
Еще один случай, когда NullReferenceExceptionsможет произойти (неправильное) использование asоператора :
Вот, Book и Carесть несовместимые типы; а Carне может быть преобразован / приведен к Book. Когда это приведение не удается, asвозвращается null. Использование mybookпосле этого вызывает NullReferenceException.
В общем, вы должны использовать приведение или as, как показано ниже:
Если вы ожидаете, что преобразование типов будет всегда успешным (т.е. вы знаете, какой объект должен быть раньше времени), тогда вам следует использовать приведение:
ComicBook cb =(ComicBook)specificBook;
Если вы не уверены в типе, но хотите попробовать использовать его как определенный тип, используйте as:
Это может случиться много раз при распаковке переменной. Я нахожу, что это часто случается в обработчиках событий после того, как я изменил тип элемента пользовательского интерфейса, но забыл обновить код.
Брендан
65
Вы используете объект, который содержит ссылку на нулевое значение. Так что это дает нулевое исключение. В этом примере строковое значение равно нулю, и при проверке его длины произошло исключение.
Пример:
stringvalue=null;if(value.Length==0)// <-- Causes exception{Console.WriteLine(value);// <-- Never reached}
Ошибка исключения:
Необработанное исключение:
System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта. в Program.Main ()
Как глубоко! Я никогда не считал нулевую константу эталонным значением. Так вот как C # абстрагирует NullPointer? B / c, как я помню в C ++, NPE может быть вызван разыменованием неинициализированного указателя (т. Е. Ref ref в c #), значением по умолчанию которого является адрес, который не выделен этому процессу (во многих случаях это будет 0, особенно в более поздних версиях C ++, которые делали автоинициализацию, которая принадлежит ОС - f вместе с ней и die beeotch (или просто поймайте сигил, с помощью которого ОС атакует ваш процесс)).
Сами
64
В то время как то, что вызывает исключения NullReferenceException и подходы, чтобы избежать / исправить такое исключение, было рассмотрено в других ответах, многие программисты еще не узнали, как самостоятельно отлаживать такие исключения во время разработки.
Теперь, когда NullReferenceException генерируется (или не обрабатывается), отладчик останавливается (помните, как установлено выше?) На строке, в которой произошло исключение. Иногда ошибку легко заметить.
Например, в следующей строке единственным кодом, который может вызвать исключение, является myStringзначение null. Это можно проверить, посмотрев в окно просмотра или запустив выражения в Immediate Window .
var x = myString.Trim();
В более сложных случаях, таких как следующие, вам нужно использовать один из методов, описанных выше (Watch или Immediate Windows), чтобы проверить выражения, чтобы определить, было ли str1NULL или str2NULL.
var x = str1.Trim()+ str2.Trim();
После того, когда исключение составляет бросок был расположен, обычно тривиальной причине задом наперед , чтобы выяснить , где нулевое значение было [неправильно] ввел -
Потратьте время, необходимое для понимания причины исключения. Осмотрите для нулевых выражений. Проверьте предыдущие выражения, которые могли привести к таким нулевым выражениям. Добавьте точки останова и пошагово пройдитесь по программе. Используйте отладчик.
1 Если Break on Throws слишком агрессивен и отладчик останавливается на NPE в .NET или сторонней библиотеке, можно использовать Break on User-Unhandled для ограничения перехвата исключений. Кроме того, VS2012 представляет Just My Code, который я также рекомендую включить.
Если вы выполняете отладку с включенным Just My Code, поведение будет немного другим. При включенном Just My Code отладчик игнорирует исключительные ситуации общеязыковой среды выполнения (CLR), которые выдаются за пределы My Code и не проходят через My Code
object o =null;DateTime d =(DateTime)o;// NullReferenceException
где преобразование распаковки (приведение) изobject (или из одного из классов System.ValueTypeили System.Enum, или из типа интерфейса) в тип значения (отличный от Nullable<>) само по себе даетNullReferenceException .
В другом направлении, A бокс преобразование изNullable<> который имеет HasValueравный falseк ссылочному типу, может дать nullссылку , которая затем может впоследствии привести к NullReferenceException. Классический пример:
DateTime? d =null;var s = d.ToString();// OK, no exception (no boxing), returns ""var t = d.GetType();// Bang! d is boxed, NullReferenceException
Иногда бокс бывает по-другому. Например, с помощью этого неуниверсального метода расширения:
Добавление случая, когда имя класса для сущности, используемой в платформе сущностей, совпадает с именем класса для файла кода веб-формы.
Предположим, у вас есть веб-форма Contact.aspx, класс codebehind которой - «Контакт», и у вас есть имя сущности «Контакт».
Затем следующий код вызовет исключение NullReferenceException при вызове context.SaveChanges ()
Contact contact =newContact{Name="Abhinav"};var context =newDataContext();
context.Contacts.Add(contact);
context.SaveChanges();// NullReferenceException at this line
Ошибка возникает, когда сущность и класс codebehind находятся в одном пространстве имен. Чтобы исправить это, переименуйте класс сущности или класс codebehind для Contact.aspx.
причина
я все еще не уверен в причине. Но всякий раз, когда какой-либо из классов сущностей расширяет System.Web.UI.Page, эта ошибка возникает.
Другой общий случай, когда можно получить это исключение, связан с классами насмешек во время модульного тестирования. Независимо от используемой среды моделирования, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом смоделированы. В частности, все свойства, на HttpContextкоторые ссылается тестируемый код, должны быть проверены.
У меня другая точка зрения, чтобы ответить на это. Такого рода ответы "что еще я могу сделать, чтобы избежать этого? "
При работе на разных уровнях , например, в приложении MVC, контроллеру нужны сервисы для вызова бизнес-операций. В таких сценариях Dependency Injection Container можно использовать для инициализации служб, чтобы избежать исключения NullReferenceException . Таким образом, это означает, что вам не нужно беспокоиться о проверке на null и просто вызывать сервисы из контроллера, как если бы они всегда были доступны (и инициализированы) в виде одиночного или прототипа.
publicclassMyController{privateServiceA serviceA;privateServiceB serviceB;publicMyController(ServiceA serviceA,ServiceB serviceB){this.serviceA = serviceA;this.serviceB = serviceB;}publicvoidMyMethod(){// We don't need to check null because the dependency injection container // injects it, provided you took care of bootstrapping it.var someObject = serviceA.DoThis();}}
-1: это обрабатывает только один сценарий - сценарий неинициализированных зависимостей. Это сценарий меньшинства для исключения NullReferenceException. В большинстве случаев это просто неправильное понимание того, как работают объекты. Следующими наиболее частыми являются другие ситуации, когда разработчик предполагал, что объект будет инициализирован автоматически.
Джон Сондерс
Внедрение зависимостей обычно не используется во избежание исключения NullReferenceException. Я не верю, что вы нашли общий сценарий здесь. В любом случае, если вы отредактируете свой ответ так, чтобы он был больше в стиле stackoverflow.com/a/15232518/76337 , то я уберу понижение.
Джон Сондерс
38
На вопрос «что мне с этим делать» может быть много ответов.
Более «формальным» способом предотвращения возникновения таких ошибок при разработке является применение проекта по контракту в вашем коде. Это означает, что вам нужно установить инварианты класса и / или даже предварительные условия и постфункции в вашей системе при разработке.
Короче говоря, инварианты класса гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушаться при обычном использовании (и, следовательно, класс не попадет в противоречивое состояние). Предварительные условия означают, что данные, переданные в качестве входных данных для функции / метода, должны соответствовать некоторым установленным ограничениям и никогда не нарушать их, а постусловия означают, что выходные данные функции / метода должны снова следовать установленным ограничениям, не нарушая их. Условия контракта никогда не должны нарушаться во время выполнения безошибочной программы, поэтому проектирование по контракту проверяется на практике в режиме отладки, хотя и отключается в выпусках , чтобы максимизировать производительность разработанной системы.
Таким образом, вы можете избежать NullReferenceExceptionслучаев, которые являются результатом нарушения установленных ограничений. Например, если вы используете свойство объекта Xв классе, а затем пытаетесь вызвать один из его методов и Xимеет нулевое значение, то это приведет к NullReferenceException:
public X {get;set;}publicvoidInvokeX(){
X.DoSomething();// if X value is null, you will get a NullReferenceException}
Но если вы установите «свойство X никогда не должно иметь нулевое значение» в качестве предварительного условия метода, то вы можете предотвратить описанный выше сценарий:
//Using code contracts:[ContractInvariantMethod]protectedvoidObjectInvariant(){Contract.Invariant( X !=null);//...}
По этой причине проект Code Contracts существует для приложений .NET.
В качестве альтернативы, дизайн по контракту может быть применен с использованием утверждений .
Я подумал добавить это, поскольку никто не упомянул об этом, и, поскольку он существует в качестве подхода, я намеревался обогатить тему.
Ник Лулудакис
2
Спасибо за обогащение темы. Я дал свое мнение о вашем дополнении. Теперь другие могут сделать то же самое.
Джон Сондерс
2
Я подумал, что это достойное дополнение к теме, поскольку это очень популярная тема. Я уже слышал о контрактах кода, и это было хорошим напоминанием об их использовании.
Проголосуй за кофе
36
A NullReferenceExceptionвыдается, когда мы пытаемся получить доступ к свойствам нулевого объекта или когда строковое значение становится пустым, а мы пытаемся получить доступ к строковым методам.
Это неверно String.Empty.ToLower()не сгенерирует исключение нулевой ссылки. Он представляет фактическую строку, хотя и пустую (то есть ""). Так как здесь есть объект для вызова ToLower(), не имеет смысла бросать туда исключение нулевой ссылки.
Кьяртан
31
TL; DR: попробуйте использовать Html.PartialвместоRenderpage
Я получал, Object reference not set to an instance of an objectкогда пытался визуализировать представление в представлении, отправив ему модель, например так:
@{MyEntity M =newMyEntity();}@RenderPage("_MyOtherView.cshtml", M);// error in _MyOtherView, the Model was Null
Отладка показала, что модель была нулевой внутри MyOtherView. Пока я не изменил это на:
@{MyEntity M =newMyEntity();}@Html.Partial("_MyOtherView.cshtml", M);
И это сработало.
Кроме того, причина, по которой мне не нужно Html.Partialбыло начинать, заключалась в том, что Visual Studio иногда бросает волнистые строки, выглядящие как ошибки, Html.Partialесли он находится внутри foreachцикла, построенного по-другому , даже если это на самом деле не ошибка:
@inheritsSystem.Web.Mvc.WebViewPage@{ViewBag.Title="Entity Index";List<MyEntity>MyEntities=newList<MyEntity>();MyEntities.Add(newMyEntity());MyEntities.Add(newMyEntity());MyEntities.Add(newMyEntity());}<div>@{foreach(var M inMyEntities){// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?@Html.Partial("MyOtherView.cshtml");}}</div>
Но я смог запустить приложение без проблем с этой «ошибкой». Я смог избавиться от ошибки, изменив структуру foreachцикла так:
@foreach(var M inMyEntities){...}
Хотя у меня такое ощущение, что Visual Studio неправильно читала амперсанды и скобки.
Также, пожалуйста, покажите, какую строку выкинуло исключение и почему.
Джон Сондерс
Ошибка произошла в MyOtherView.cshtml, который я здесь не включил, потому что Модель не была отправлена должным образом (она была Null), поэтому я знал, что ошибка была в том, как я отправлял Модель.
Трэвис Хитер,
22
Что вы можете с этим поделать?
Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но есть очень мало о том, как предотвратить проблему или, по крайней мере, облегчить ее обнаружение.
Проверьте аргументы
Например, методы могут проверять различные аргументы, чтобы определить ArgumentNullException, являются ли они пустыми, и выдавать исключение, явно созданное для этой конкретной цели.
Конструктор для ArgumentNullExceptioneven принимает имя параметра и сообщение в качестве аргумента, чтобы вы могли точно сказать разработчику, в чем заключается проблема.
publicvoidDoSomething(MyObject obj){if(obj ==null){thrownewArgumentNullException("obj","Need a reference to obj.");}}
Используйте инструменты
Есть также несколько библиотек, которые могут помочь. Например, «Resharper» может выдавать вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute
Есть «Microsoft Code Contracts», где вы используете синтаксис, подобный тому, Contract.Requires(obj != null)который дает вам время выполнения и проверку компиляции: Введение в Code Contracts .
Также есть «PostSharp», который позволит вам просто использовать такие атрибуты:
publicvoidDoSometing([NotNull] obj)
Сделав это и сделав PostSharp частью вашего процесса сборки, objвы будете проверяться на ноль во время выполнения. Смотрите: PostSharp нулевая проверка
Решение с простым кодом
Или вы всегда можете написать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать для перехвата нулевых ссылок. Он смоделирован по той же концепции, что и Nullable<T>:
[System.Diagnostics.DebuggerNonUserCode]publicstructNotNull<T>where T:class{private T _value;public T Value{get{if(_value ==null){thrownewException("null value not allowed");}return _value;}set{if(value==null){thrownewException("null value not allowed.");}
_value =value;}}publicstaticimplicitoperator T(NotNull<T> notNullValue){return notNullValue.Value;}publicstaticimplicitoperatorNotNull<T>(T value){returnnewNotNull<T>{Value=value};}}
Вы будете использовать очень похоже на то же самое, что и вы Nullable<T>, за исключением того, что вы делаете совершенно противоположное - не допустить null. Вот некоторые примеры:
NotNull<Person> person =null;// throws exceptionNotNull<Person> person =newPerson();// OKNotNull<Person> person =GetPerson();// throws exception if GetPerson() returns null
NotNull<T>неявно приведен к и от, Tтак что вы можете использовать его где угодно. Например, вы можете передать Personобъект в метод, который принимает NotNull<Person>:
Person person =newPerson{Name="John"};WriteName(person);publicstaticvoidWriteName(NotNull<Person> person){Console.WriteLine(person.Value.Name);}
Как вы можете видеть выше, как с nullable, вы получите доступ к базовому значению через Valueсвойство. Кроме того, вы можете использовать явное или неявное приведение, вы можете увидеть пример с возвращаемым значением ниже:
Person person =GetPerson();publicstaticNotNull<Person>GetPerson(){returnnewPerson{Name="John"};}
Или вы можете даже использовать его, когда метод просто возвращает T(в данном случае Person), выполняя приведение. Например, следующий код будет похож на код выше:
Person person =(NotNull<Person>)GetPerson();publicstaticPersonGetPerson(){returnnewPerson{Name="John"};}
Объединить с расширением
Объедините NotNull<T>с методом расширения, и вы сможете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:
[System.Diagnostics.DebuggerNonUserCode]publicstaticclassNotNullExtension{publicstatic T NotNull<T>(this T @this)where T:class{if(@this==null){thrownewException("null value not allowed");}return@this;}}
И вот пример того, как это можно использовать:
var person =GetPerson().NotNull();
GitHub
Для справки, я сделал приведенный выше код доступным на GitHub, вы можете найти его по адресу:
В C # 6.0 введен «нулевой оператор», который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты и, если какой-либо из них является nullцелым выражением, возвращается null.
Это уменьшает количество нулевых проверок, которые вы должны сделать в некоторых случаях. Синтаксис ставит знак вопроса перед каждой точкой. Возьмите следующий код для примера:
var address = country?.State?.County?.City;
Представьте, что countryэто объект типа Country, у которого есть свойство с именем Stateи так далее. Если country, State, Countyили Cityэто nullто address will beнулевой . Therefore you only have to check whetherадрес isnull`.
Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.
Встроенный как Nullable?
В C # есть хорошее обозначение: Nullable<T>вы можете сделать что-то обнуляемое, поставив знак вопроса после такого типа int?.
Было бы хорошо , если бы C # было что - то вроде NotNull<T>структуры выше и имел подобную стенографии, может быть восклицательным знаком , так что вы могли бы написать что - то вроде (!) public void WriteName(Person! person).
Никогда не выбрасывайте исключение NullReferenceException
Джон Сондерс
@JohnSaunders смею спросить почему? (Серьезно, хотя почему?)
Луис Перес
2
NullReferenceException предназначено, чтобы быть брошенным CLR. Это означает, что ссылка на ноль произошла. Это не означает, что ссылка на ноль будет иметь место, за исключением того, что вы ловко проверили сначала.
Джон Сондерс
Я понимаю вашу точку зрения о том, как это может сбить с толку. Я обновил его до обычного исключения для этого примера и пользовательского исключения в GitHub.
Луис Перес
Отличный ответ на такой основной вопрос. Это не так плохо, когда ваш код не работает. Это ужасно, когда он приходит из какой-то коммерческой сторонней библиотеки, на которую вы полагаетесь, и служба поддержки клиентов настаивает на том, что именно ваш код вызывает проблему. И вы не совсем уверены, что это не так, и весь проект может быть остановлен ... Я действительно думаю, что это может сделать подходящую эпитафию для моей надгробной плиты: «Ссылка на объект не установлена на экземпляр объекта».
Даррел Ли
10
Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я добавлю их:
Крайний случай № 1: одновременный доступ к словарю
Общие словари в .NET не являются поточно-ориентированными и иногда могут выдавать NullReferenceили даже (чаще) KeyNotFoundExceptionпри попытке получить доступ к ключу из двух параллельных потоков. Исключение весьма обманчиво в этом случае.
Крайний случай № 2: небезопасный код
Если a NullReferenceExceptionгенерируется unsafeкодом, вы можете посмотреть на переменные-указатели и проверить их на наличие IntPtr.Zeroчего-либо. Это то же самое («исключение нулевого указателя»), но в небезопасном коде переменные часто приводятся к типам значений / массивам и т. Д., И вы бьетесь головой о стену, задаваясь вопросом, как тип значения может бросить это исключение.
(Кстати, еще одна причина не использовать небезопасный код, если он вам не нужен)
Ваш словарный пример не является крайним случаем. Если объект не является потокобезопасным, то использование его из нескольких потоков приводит к случайным результатам. Ваш небезопасный пример кода отличается от того, nullчем?
Джон Сондерс
10
Вы можете исправить NullReferenceException чистым способом с помощью Null-условных операторов в c # 6 и написать меньше кода для обработки нулевых проверок.
Он используется для проверки на нулевое значение перед выполнением операции доступа к члену (?.) Или индекса (? [).
пример
var name = p?.Spouse?.FirstName;
эквивалентно:
if(p !=null){if(p.Spouse!=null){
name = p.Spouse.FirstName;}}
В результате имя будет нулевым, когда p равно нулю или когда p.Spouse равно нулю.
В противном случае имени переменной будет присвоено значение p.Spouse.FirstName.
Строка ошибки «Ссылка на объект не установлена для экземпляра объекта.» Гласит, что вы не назначили объект экземпляра для ссылки на объект, и все же вы получаете доступ к свойствам / методам этого объекта.
например: допустим, у вас есть класс с именем myClass, и он содержит одно свойство prop1.
publicClass myClass
{publicint prop1 {get;set;}}
Теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:
publicclassDemo{publicvoid testMethod(){
myClass ref=null;ref.prop1 =1;//This line throws error}}
вышеприведенная строка выдает ошибку, поскольку ссылка на класс myClass объявлена, но не создана, или экземпляр объекта не назначен для ссылки на этот класс.
Чтобы это исправить, вы должны создать экземпляр (назначить объект для ссылки на этот класс).
NullReferenceException или ссылка на объект, не установленная для экземпляра объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:
Предположим, что у вас есть класс с именем Student.
Как видно из приведенного выше кода, оператор
Student s - только объявляет переменную типа Student, обратите внимание, что на этом этапе класс Student не создается. Следовательно, когда выполняется оператор s.GetFullName () , он генерирует исключение NullReferenceException.
Вы пытаетесь получить доступ к объекту, который не создан или в данный момент отсутствует в памяти.
Итак, как справиться с этим:
Отладьте и дайте отладчику сломаться ... Он напрямую приведет вас к сломанной переменной ... Теперь ваша задача просто исправить это ... Используя ключевое слово new в соответствующем месте.
Если это вызвано в некоторых командах базы данных, потому что объект не присутствует, тогда все, что вам нужно сделать, это сделать нулевую проверку и обработать ее:
if(i ==null){// Handle this}
Сложнее всего ... если GC уже собрал объект ... Обычно это происходит, если вы пытаетесь найти объект с помощью строк ... То есть, находя его по имени объекта, может случиться так, что GC может уже Вычистил это ... Это трудно найти и станет большой проблемой ... Лучший способ справиться с этим - делать нулевые проверки везде, где это необходимо в процессе разработки. Это сэкономит вам много времени.
Под поиском по имени я подразумеваю некоторую инфраструктуру, позволяющую вам FIndObjects использовать строки, и код может выглядеть следующим образом: FindObject ("ObjectName");
Если у вас есть ссылка на объект, то GC никогда не очищает его
Джон Сондерс
2
если вы используете такие вещи, как FindObject («Имя объекта»), GC никогда не узнает заранее, что вы собираетесь ссылаться на этот объект ... это то, что он пытался объяснить .. это происходит во время выполнения
Akash Gutha
2
Есть некоторые платформы, которые предоставляют эту функциональность в C #, такие как Unity. вопрос не имеет ничего общего с BCl. Прежде чем критиковать, поищите в интернете множество функций, подобных им, и для доброй информации я даже использую ее ежедневно. Теперь, пожалуйста, скажите мне, как ответ не имеет никакого смысла.
Примеры, которые я видел в вашей ссылке, присваивают результаты GameObject.Find полю участника. Это ссылка, и GC не будет собирать ее, пока не будет собран содержащий объект.
Джон Сондерс
1
Буквально самый простой способ исправить NullReferenceExeption имеет два способа. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (hardbody), эта переменная будет начинаться с нуля, когда вы начнете свою игру.
Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.
Я буду использовать переменную RigidBody в качестве примера.
Мы можем действительно легко добавить данные несколькими способами:
Добавьте RigidBody к своему объекту с помощью AddComponent> Physics> Rigidbody.
Затем перейдите в свой сценарий и введите. rb = GetComponent<Rigidbody>();
Эта строка кода лучше всего работает под вашим Start()илиAwake() функциями.
Вы можете добавить компонент программно и назначить переменную одновременно одной строкой кода: rb = AddComponent<RigidBody>();
Дополнительные примечания: Если вы хотите, чтобы Unity добавила компонент к вашему объекту, и, возможно, вы забыли добавить его, вы можете напечатать [RequireComponent(typeof(RigidBody))]над объявлением класса (пробел под всеми вашими использованиями).
Наслаждайтесь игрой и получайте удовольствие!
Если мы рассмотрим распространенные сценарии, в которых это исключение может быть выброшено, доступ к свойствам осуществляется с помощью объекта сверху.
Пример:
string postalcode=Customer.Address.PostalCode;//if customer or address is null , this will through exeption
здесь, если адрес равен нулю, то вы получите NullReferenceException.
Таким образом, в качестве практики мы всегда должны использовать проверку null, прежде чем обращаться к свойствам в таких объектах (особенно в общем)
string postalcode=Customer?.Address?.PostalCode;//if customer or address is null , this will return null, without through a exception
Это в основном является нулевым ссылочным исключением . Как заявляет Microsoft,
Исключение NullReferenceException выдается при попытке доступа к члену типа, значение которого равно нулю.
Что это обозначает?
Это означает, что если какой-либо участник, который не имеет никакого значения, и мы заставляем этого участника выполнять определенную задачу, то система, несомненно, бросит сообщение и скажет:
«Эй, подождите, у этого члена нет значений, поэтому он не может выполнить задачу, которую вы передаете».
Само исключение говорит, что на что-то ссылаются, но чье значение не устанавливается. Таким образом, это означает, что это происходит только при использовании ссылочных типов, поскольку типы значений не могут быть обнуляемыми.
NullReferenceException не произойдет, если мы используем члены типа Value.
Приведенный выше код показывает простую строку, которой присваивается нулевое значение.
Теперь, когда я пытаюсь напечатать длину строки str , я получаю сообщение о необработанном исключении типа «System.NullReferenceException», потому что член str указывает на ноль и не может быть никакой длины ноль.
« NullReferenceException » также происходит , когда мы забываем экземпляр ссылочного типа.
Предположим, у меня есть метод класса и члена. Я не создал экземпляр своего класса, а только назвал свой класс. Теперь, если я попытаюсь использовать метод, компилятор выдаст ошибку или выдаст предупреждение (в зависимости от компилятора).
classProgram{staticvoidMain(string[] args){MyClass1 obj;
obj.foo();//Use of unassigned local variable 'obj'}}publicclassMyClass1{internalvoid foo(){Console.WriteLine("hello from foo");}}
Компилятор для приведенного выше кода выдает ошибку, что переменная obj не назначена, что означает, что наша переменная имеет нулевые значения или ничего. Компилятор для приведенного выше кода выдает ошибку, что переменная obj не назначена, что означает, что наша переменная имеет нулевые значения или ничего.
Почему это происходит?
NullReferenceException возникает из-за нашей ошибки в том, что мы не проверили значение объекта. Мы часто оставляем значения объектов непроверенными в разработке кода.
Это также возникает, когда мы забываем создавать экземпляры наших объектов. Использование методов, свойств, коллекций и т. Д., Которые могут возвращать или устанавливать нулевые значения, также может быть причиной этого исключения.
Как этого можно избежать?
Существуют различные способы и способы избежать этого известного исключения:
Явная проверка. Мы должны придерживаться традиции проверки объектов, свойств, методов, массивов и коллекций на предмет наличия нулевых значений. Это может быть просто реализовано с использованием условных операторов, таких как if-else, if-else и т. Д.
Обработка исключений: один из важных способов управления этим исключением. Используя простые блоки try-catch-finally, мы можем контролировать это исключение, а также вести его журнал. Это может быть очень полезно, когда ваше приложение находится на стадии разработки.
Нулевые операторы: нулевой оператор слияния и нулевые условные операторы также могут быть полезны при задании значений для объектов, переменных, свойств и полей.
Отладчик: Для разработчиков у нас есть большое оружие отладки. Если мы столкнулись с NullReferenceException во время разработки, мы можем использовать отладчик, чтобы добраться до источника исключения.
Встроенный метод. Системные методы, такие как GetValueOrDefault (), IsNullOrWhiteSpace () и IsNullorEmpty (), проверяют наличие нулевых значений и присваивают значение по умолчанию, если существует нулевое значение.
Здесь уже есть много хороших ответов. Вы также можете проверить более подробное описание с примерами в моем блоге .
Вы в основном скопировали половину этого сообщения в блоге и не добавили ничего нового, к которому не относятся существующие ответы.
CodeCaster
@codecaster Говорят ли вы копирование, когда вы переписываете резюме из своего блога. Я знаю, что в моем ответе нет ничего нового и ничего нового, чего нет в предыдущих ответах, но я хочу внести свой вклад более изощренным образом и позволить другим понять то, что я понял. Будем рады, даже если это поможет одному человеку. Добросовестно.
Васим
-4
Если вы получаете это сообщение во время сохранения или компиляции сборки, просто закройте все файлы и затем откройте любой файл для компиляции и сохранения.
Для меня причина была в том, что я переименовал файл, а старый файл все еще был открыт.
Ответы:
В чем причина?
Нижняя граница
Вы пытаетесь использовать то, что есть
null
(илиNothing
в VB.NET). Это означает, что вы либо установили егоnull
, либо никогда вообще ничего не устанавливали.Как и все остальное,
null
обходит вокруг. Еслиnull
в методе «A», может быть , что метод «В» принятnull
к методу «A».null
может иметь разные значения:NullReferenceException
.null
чтобы указать, что значимых доступных значений нет. Обратите внимание, что C # имеет концепцию типов данных, допускающих значение NULL для переменных (например, таблицы базы данных могут иметь поля NULL), которые можноnull
указывать, чтобы указать, что в них нет сохраненного значения, например,int? a = null;
когда знак вопроса указывает, что ему разрешено хранить нуль в переменнаяa
. Вы можете проверить это либо с,if (a.HasValue) {...}
либо сif (a==null) {...}
. Обнуляемые переменные, как вa
этом примере, позволяют получить доступ к значениюa.Value
явно или просто как обычноa
.Обратите внимание , что доступ к нему через
a.Value
ВыдаетInvalidOperationException
вместоNullReferenceException
еслиa
ISnull
- вы должны выполнить проверку заранее, т. е. если у вас есть другая переменная, которая может иметь значение nullable,int b;
вы должны выполнять назначения, такие какif (a.HasValue) { b = a.Value; }
или более короткиеif (a != null) { b = a; }
.Остальная часть этой статьи более подробно раскрывает ошибки, которые часто допускают многие программисты, что может привести к
NullReferenceException
.Более конкретно
runtime
МетанииNullReferenceException
всегда означает то же самое: вы пытаетесь использовать ссылку, и ссылка не инициализируется (или он был когда - то инициализируется, но не больше не инициализирован).Это означает, что ссылка есть
null
, и вы не можете получить доступ к членам (таким как методы) черезnull
ссылку. Самый простой случай:Это приведет к
NullReferenceException
появлению второй строки, потому что вы не можете вызвать метод экземпляраToUpper()
дляstring
ссылки, указывающей наnull
.Отладка
Как вы находите источник
NullReferenceException
? Помимо рассмотрения самого исключения, которое будет сгенерировано именно в том месте, где оно происходит, применяются общие правила отладки в Visual Studio: устанавливайте стратегические контрольные точки и проверяйте свои переменные , наведя указатель мыши на их имена, открывая ( Быстро) Наблюдайте за окном или используя различные панели отладки, такие как Locals и Autos.Если вы хотите узнать, где находится ссылка или нет, щелкните правой кнопкой мыши ее имя и выберите «Найти все ссылки». Затем вы можете установить точку останова в каждом найденном месте и запустить вашу программу с подключенным отладчиком. Каждый раз, когда отладчик прерывает работу на такой точке останова, вам нужно определить, ожидаете ли вы, что ссылка не равна нулю, проверить переменную и убедиться, что она указывает на экземпляр, когда вы этого ожидаете.
Следуя этой программе, вы можете найти место, где экземпляр не должен быть нулевым, и почему он не установлен должным образом.
Примеры
Некоторые распространенные сценарии, в которых может быть выдано исключение:
общий
Если ref1 или ref2 или ref3 равны нулю, вы получите
NullReferenceException
. Если вы хотите решить проблему, то выясните, какая из них равна нулю, переписав выражение в его более простой эквивалент:В частности, в
HttpContext.Current.User.Identity.Name
, тоHttpContext.Current
может быть пустым, илиUser
свойство может быть пустым, илиIdentity
свойство может быть пустым.непрямой
Если вы хотите избежать нулевой ссылки дочернего (Person), вы можете инициализировать ее в конструкторе родительского (Book) объекта.
Инициализаторы вложенных объектов
То же самое относится и к инициализаторам вложенных объектов:
Это переводится как
Пока используется
new
ключевое слово, оно создает только новый экземплярBook
, но не новый экземплярPerson
, поэтомуAuthor
свойство остается прежнимnull
.Инициализаторы вложенных коллекций
Вложенная коллекция
Initializers
ведет себя так же:Это переводится как
new Person
Только создает экземплярPerson
, ноBooks
коллекция до сих порnull
.Initializer
Синтаксис коллекции не создает коллекциюp1.Books
, он только переводит вp1.Books.Add(...)
операторы.массив
Элементы массива
Зубчатые массивы
Коллекция / Список / Словарь
Переменная диапазона (косвенная / отложенная)
Мероприятия
открытый класс Form1 {частный заказчик;
}
Эту проблему можно решить, следуя соглашению о добавлении префикса к полям с подчеркиванием:
Жизненный цикл страницы ASP.NET:
Значения сеанса ASP.NET
ASP.NET MVC модели пустого представления
Если исключение возникает при обращении к свойству в
@Model
inASP.NET MVC View
, вам нужно понимать, чтоModel
get задается в вашем методе действия, когда выreturn
просматриваете. Когда вы возвращаете пустую модель (или свойство модели) из вашего контроллера, исключение возникает, когда представления обращаются к нему:Порядок и события создания элемента управления WPF
WPF
элементы управления создаются во время вызоваInitializeComponent
в порядке их появления в визуальном дереве. ANullReferenceException
будет вызываться в случае ранее созданных элементов управления с обработчиками событий и т. Д., Которые срабатывают приInitializeComponent
обращении к недавно созданным элементам управления.Например :
Здесь
comboBox1
создано раньшеlabel1
. ЕслиcomboBox1_SelectionChanged
попытка сослаться на `label1, он еще не был создан.Изменение порядка объявлений в
XAML
(т. Е. Перечислениеlabel1
ранееcomboBox1
, игнорируя вопросы философии дизайна, по крайней мере, решило быNullReferenceException
здесь.В ролях с
as
Это не бросает,
InvalidCastException
но возвращает,null
когда приведение не удается (и когдаsomeObject
само по себе является нулевым). Так что знайте об этом.LINQ
FirstOrDefault()
иSingleOrDefault()
Простые версии
First()
иSingle()
исключения, когда нет ничего. Версии «OrDefault» в этом случае возвращают ноль. Так что знайте об этом.для каждого
foreach
бросает при попытке перебрать нулевую коллекцию. Обычно вызвано неожиданнымnull
результатом от методов, которые возвращают коллекции.Более реалистичный пример - выберите узлы из XML-документа. Выдает, если узлы не найдены, но начальная отладка показывает, что все свойства действительны:
Способов избежать
Явно проверяйте
null
и игнорируйте нулевые значения.Если вы ожидаете, что ссылка иногда будет нулевой, вы можете проверить ее на наличие
null
до доступа к членам экземпляра:Явно проверьте
null
и укажите значение по умолчанию.Вызов методов, которые вы ожидаете вернуть, может возвращать экземпляр
null
, например, когда искомый объект не может быть найден. Вы можете вернуть значение по умолчанию, если это так:Явно проверяйте
null
из вызовов методов и создавайте пользовательское исключение.Вы также можете выдать пользовательское исключение, только чтобы перехватить его в вызывающем коде:
Используйте,
Debug.Assert
если значение никогда не должно бытьnull
, чтобы поймать проблему раньше, чем возникнет исключение.Если во время разработки вы знаете, что метод может, но никогда не должен возвращаться
null
, вы можете использовать егоDebug.Assert()
для прерывания как можно скорее, когда это произойдет:Хотя эта проверка не закончится в вашей сборке релиза , из-за чего она
NullReferenceException
снова выдаст команду воbook == null
время выполнения в режиме релиза.Используйте
GetValueOrDefault()
дляnullable
типов значений, чтобы обеспечить значение по умолчанию, когда они естьnull
.Используйте оператор объединения нулей:
??
[C #] илиIf()
[VB].Сокращение для предоставления значения по умолчанию, когда
null
встречается:Используйте оператор условия null:
?.
или?[x]
для массивов (доступно в C # 6 и VB.NET 14):Это также иногда называют безопасной навигацией или оператором Элвиса (после его формы). Если выражение в левой части оператора является нулевым, то правая часть не будет вычисляться, и вместо него будет возвращено нулевое значение. Это означает, что такие случаи:
Если у человека нет заголовка, это вызовет исключение, потому что он пытается вызвать
ToUpper
свойство с нулевым значением.В
C# 5
и ниже, это может быть защищено с:Теперь переменная заголовка будет иметь значение null вместо исключения. C # 6 вводит более короткий синтаксис для этого:
Это приведет к тому, что переменная заголовка будет
null
, и вызовToUpper
не будет выполнен, еслиperson.Title
естьnull
.Конечно, вам все равно нужно проверить
title
наличие нуля или использовать оператор условия null вместе с оператором объединения нулей (??
), чтобы задать значение по умолчанию:Аналогично, для массивов вы можете использовать
?[i]
следующее:Это сделает следующее: Если значение
myIntArray
равно NULL, выражение возвращает значение NULL, и вы можете безопасно проверить его. Если он содержит массив, он будет делать то же самое, что и:elem = myIntArray[i];
и возвращаетi<sup>th</sup>
элемент.Использовать нулевой контекст (доступно в C # 8):
Представленные
C# 8
там нулевые контексты и ссылочные типы, допускающие значение NULL, выполняют статический анализ переменных и выдают предупреждение компилятору, если значение может быть потенциально нулевым или для него установлено значение NULL. Обнуляемые ссылочные типы позволяют типам быть явно пустыми.Обнуляемый контекст аннотации и обнуляемый контекст предупреждения могут быть установлены для проекта с использованием
Nullable
элемента в вашемcsproj
файле. Этот элемент настраивает, как компилятор интерпретирует обнуляемость типов и какие предупреждения генерируются. Допустимые настройки:Обнуляемый ссылочный тип отмечается с использованием того же синтаксиса, что и типы значений, допускающие обнуляемое значение: a
?
добавляется к типу переменной.Специальные методы отладки и исправления нулевых разыменований в итераторах
C#
поддерживает "блоки итераторов" (называемые "генераторами" в некоторых других популярных языках). Исключения нулевого разыменования могут быть особенно сложными для отладки в блоках итераторов из-за отложенного выполнения:Если
whatever
результаты вnull
тоMakeFrob
кинет. Теперь вы можете подумать, что правильно сделать следующее:Почему это не так? Поскольку блок итератора фактически не выполняется до
foreach
! ВызовGetFrobs
просто возвращает объект, который при повторении запускает блок итератора.Путем написания нулевой проверки, подобной этой, вы предотвращаете разыменование нулевого значения, но перемещаете исключение нулевого аргумента в точку итерации , а не в точку вызова , и это очень сбивает с толку при отладке .
Правильное исправление:
То есть создайте приватный вспомогательный метод, который имеет логику блока итератора, и метод публичной поверхности, который выполняет нулевую проверку и возвращает итератор. Теперь, когда
GetFrobs
вызывается, проверка на ноль происходит немедленно, а затемGetFrobsForReal
выполняется, когда последовательность повторяется.Если вы изучите источник ссылки
LINQ
на Объекты, вы увидите, что эта техника используется повсеместно. Это немного более неуклюже, чтобы написать, но это делает отладку ошибок недействительности намного легче. Оптимизируйте свой код для удобства звонящего, а не для удобства автора .Примечание о нулевых разыменованиях в небезопасном коде
C#
имеет «небезопасный» режим, который, как следует из названия, чрезвычайно опасен, поскольку обычные механизмы безопасности, которые обеспечивают безопасность памяти и безопасность типов, не применяются. Вы не должны писать небезопасный код, если у вас нет глубокого и глубокого понимания того, как работает память .В небезопасном режиме вы должны знать о двух важных фактах:
Чтобы понять, почему это так, это помогает понять, как .NET в первую очередь создает исключения с нулевым разыменованием. (Эти сведения относятся к .NET, работающему в Windows; другие операционные системы используют аналогичные механизмы.)
Память виртуализирована в
Windows
; каждый процесс получает пространство виртуальной памяти из множества «страниц» памяти, которые отслеживаются операционной системой. На каждой странице памяти установлены флаги, которые определяют, как ее можно использовать: чтение, запись, выполнение и т. Д. Самая нижняя страница помечена как «выдает ошибку, если когда-либо используется каким-либо образом».И нулевой указатель, и нулевая ссылка в нем
C#
внутренне представлены как нулевое число, и поэтому любая попытка разыменовать его в соответствующее хранилище памяти приводит к ошибке операционной системы. Затем среда выполнения .NET обнаруживает эту ошибку и превращает ее в исключение нулевой разыменования.Вот почему разыменование как нулевого указателя, так и нулевой ссылки приводит к одному и тому же исключению.
Как насчет второго пункта? Разыменование любого недопустимого указателя, который попадает на нижнюю страницу виртуальной памяти, вызывает ту же ошибку операционной системы и, следовательно, то же исключение.
Почему это имеет смысл? Хорошо, предположим, что у нас есть структура, содержащая два целых числа, и неуправляемый указатель, равный нулю. Если мы попытаемся разыменовать второй тип int в структуре,
CLR
он не будет пытаться получить доступ к хранилищу в нулевом местоположении; он получит доступ к хранилищу в расположении четыре. Но логически это нулевая разыменование, потому что мы получаем по этому адресу через нуль.Если вы работаете с небезопасным кодом и получаете исключение нулевой разыменования, просто имейте в виду, что указатель-нарушитель не обязательно должен быть нулевым. Это может быть любое место на самой нижней странице, и будет сделано это исключение.
источник
new Book { Author = { Age = 45 } };
Как внутренняя инициализация даже ... Я не могу представить ситуацию, когда внутренний init будет работать, но он компилируется и работает intellisense ... Разве что для структур?Исключение NullReference - Visual Basic
NullReference Exception
Для Visual Basic ничем не отличается от такового в C # . В конце концов, они оба сообщают об одном и том же исключении, определенном в .NET Framework, которое они оба используют. Причины, уникальные для Visual Basic, встречаются редко (возможно, только одна).В этом ответе будут использоваться термины, синтаксис и контекст Visual Basic. Используемые примеры взяты из большого количества прошлых вопросов о переполнении стека. Это максимально уместность, используя виды ситуаций , часто видели в сообщениях. Немного больше объяснений также предоставляется тем, кому это может понадобиться. Пример, похожий на ваш, очень вероятно, приведен здесь.
Замечания:
NullReferenceException
(NRE), как его найти, как его исправить и как его избежать. NRE может быть вызвано многими способами, так что вряд ли это будет ваша единственная встреча.Основное значение
Сообщение «Объект не установлен в экземпляр объекта» означает, что вы пытаетесь использовать объект, который не был инициализирован. Это сводится к одному из них:
В поисках причины
Так как проблема заключается в ссылке на объект
Nothing
, ответ заключается в том, чтобы изучить их, чтобы выяснить, какая из них. Затем определите, почему он не инициализирован. Наведите курсор на различные переменные, и Visual Studio (VS) покажет их значения - виновник будетNothing
.Вам также следует удалить все блоки Try / Catch из соответствующего кода, особенно те, в которых нет ничего в блоке Catch. Это приведет к сбою вашего кода при попытке использовать объект, который есть
Nothing
. Это то, что вы хотите, потому что он будет определять точное местоположение проблемы и позволит вам определить объект, вызывающий ее.А
MsgBox
в улове, который отображаетError while...
, мало поможет. Этот метод также приводит к очень плохим вопросам переполнения стека, потому что вы не можете описать фактическое исключение, задействованный объект или даже строку кода, где это происходит.Вы также можете использовать
Locals Window
( Debug -> Windows -> Locals ) для проверки ваших объектов.После того, как вы знаете, в чем и где проблема, ее обычно довольно легко исправить и быстрее, чем опубликовать новый вопрос.
Смотрите также:
Примеры и средства правовой защиты
Объекты класса / Создание экземпляра
Проблема в том, что
Dim
не создает объект CashRegister ; он объявляет только переменную с именемreg
этого типа. Объявление переменной объекта и создание экземпляра - это две разные вещи.средство
New
Оператор часто может быть использован для создания экземпляра при объявлении его:Когда уместно создать экземпляр позже:
Примечание. Не используйте
Dim
снова в процедуре, включая конструктор (Sub New
):Это создаст локальную переменную,
reg
которая существует только в этом контексте (подпункте).reg
Переменной с уровнем модуля ,Scope
который вы будете использовать в любом другом месте остаетсяNothing
.Чтобы было понятно,
Dim
(илиPrivate
) объявляет только переменную и ееType
. Объем переменной - существует ли она для всего модуля / класса или является локальным для процедуры - определяется , где она объявлена.Private | Friend | Public
определяет уровень доступа, а не Scope .Для получения дополнительной информации см .:
Массивы
Массивы также должны быть созданы:
Этот массив только объявлен, но не создан. Существует несколько способов инициализации массива:
Примечание: Начиная с VS 2010, при инициализации локальный массив с использованием буквальным и
Option Infer
, тоAs <Type>
иNew
элементы не являются обязательными:Тип данных и размер массива выводятся из назначаемых данных. Объявления уровня класса / модуля все еще требуют
As <Type>
сOption Strict
:Пример: массив объектов класса
Массив был создан, но
Foo
объекты в нем нет.средство
С помощью a
List(Of T)
будет довольно сложно иметь элемент без действительного объекта:Для получения дополнительной информации см .:
Списки и Коллекции
Коллекции .NET (из которых существует множество разновидностей - списки, словарь и т. Д.) Также должны быть созданы или созданы.
Вы получаете то же исключение по той же причине -
myList
было объявлено, но экземпляр не создан. Средство защиты такое же:Обычный недосмотр - это класс, который использует коллекцию
Type
:Любая процедура приведет к NRE, потому что
barList
она только объявлена, а не создана. Создание экземпляраFoo
не будет также создавать экземпляр внутреннегоbarList
. Возможно, это было сделано в конструкторе:Как и раньше, это неверно:
Для получения дополнительной информации см.
List(Of T)
Класс .Объекты провайдера данных
Работа с базами данных представляет много возможностей для NullReference , потому что может быть много объектов (
Command
,Connection
,Transaction
,Dataset
,DataTable
,DataRows
....) в использовании сразу. Примечание: не имеет значения, какой поставщик данных вы используете - MySQL, SQL Server, OleDB и т. Д. - концепции одинаковы.Пример 1
Как и прежде,
ds
объект Dataset был объявлен, но экземпляр не был создан.DataAdapter
Заполнит существующийDataSet
, не создать. В этом случае, посколькуds
это локальная переменная, IDE предупреждает вас о том, что это может произойти:Когда объявлено как переменная уровня модуля / класса, как, кажется, имеет место
con
, компилятор не может знать, был ли объект создан вышестоящей процедурой. Не игнорируйте предупреждения.средство
Пример 2
Опечатка проблема здесь:
Employees
противEmployee
. ИмяDataTable
сотрудника не было создано, поэтомуNullReferenceException
результаты пытаются получить к нему доступ. Другая потенциальная проблема заключается в предположении, что этоItems
может быть не так, когда SQL включает предложение WHERE.средство
Поскольку при этом используется одна таблица, использование
Tables(0)
позволит избежать орфографических ошибок. ЭкспертизаRows.Count
также может помочь:Fill
это функция, возвращающая числоRows
затронутых, которая также может быть проверена:Пример 3
DataAdapter
Обеспечит ,TableNames
как показано в предыдущем примере, но не обрабатывает имена из SQL или базы данных таблицы. В результатеds.Tables("TICKET_RESERVATION")
ссылается на несуществующую таблицу.Устранение такой же, ссылки на таблицу с помощью индекса:
Смотрите также DataTable Class .
Пути к объектам / вложенные
Код только тестирует и
Items
то и другое,myFoo
иBar
может также быть Nothing. Средство защиты состоит в том, чтобы проверять всю цепочку или путь объектов по одному:AndAlso
является важным. Последующие тесты не будут выполнены, как толькоFalse
будет встречено первое условие. Это позволяет коду безопасно «углубляться» в объект (ы) по одному «уровню» за раз, оцениваяmyFoo.Bar
только после того, как (и если)myFoo
будет определено, что он действителен. Цепочки объектов или пути могут быть довольно длинными при кодировании сложных объектов:Невозможно ссылаться на что-либо «вниз по течению» от
null
объекта. Это также относится к элементам управления:Здесь
myWebBrowser
илиDocument
может быть Nothing илиformfld1
элемент может не существовать.UI Controls
Среди прочего, этот код не предполагает, что пользователь, возможно, не выбрал что-то в одном или нескольких элементах управления пользовательского интерфейса.
ListBox1.SelectedItem
вполне может бытьNothing
, поэтомуListBox1.SelectedItem.ToString
приведет к NRE.средство
Проверьте данные перед их использованием (также используйте
Option Strict
и параметры SQL):Кроме того, вы можете использовать
(ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Visual Basic Forms
Это довольно распространенный способ получить NRE. В C #, в зависимости от того, как это закодировано, IDE сообщит, что
Controls
не существует в текущем контексте, или «не может ссылаться на нестатический член». Так что, в некоторой степени, это ситуация только для VB. Это также сложно, потому что это может привести к каскаду сбоев.Массивы и коллекции не могут быть инициализированы таким образом. Этот код инициализации будет запущен до того, как конструктор создаст
Form
илиControls
. В результате:somevar
Назначение приведет к немедленному ЯРДУ , потому что ничего не имеет.Text
свойстваСсылка на элементы массива позже приведет к NRE. Если вы сделаете это
Form_Load
из-за странной ошибки, IDE может не сообщить об исключении, когда это произойдет. Исключение появится позже, когда ваш код попытается использовать массив. Это «тихое исключение» подробно описано в этом посте . Для наших целей ключевым моментом является то, что когда происходит что-то катастрофическое во время создания формы (Sub New
илиForm Load
события), исключения могут остаться незамеченными, код выходит из процедуры и просто отображает форму.Поскольку никакой другой код в вашем
Sub New
илиForm Load
событии не будет выполняться после NRE, многие другие вещи можно оставить неинициализированными.Обратите внимание, что это относится ко всем без исключения ссылкам на элементы управления и компонентов, что делает их недопустимыми, если они:
Частичное Средство
Любопытно , что VB не дает предупреждение, а средство для объявить контейнеры на уровне формы, но инициализировать их в обработчик события загрузки формы , когда элементы управления делают существует. Это можно сделать,
Sub New
если ваш код находится послеInitializeComponent
вызова:Код массива еще может быть не в лесу. Любые элементы управления, которые находятся в элементе управления контейнера (например,
GroupBox
илиPanel
), не будут найдены вMe.Controls
; они будут в коллекции Controls этой Panel или GroupBox. Также не будет возвращен элемент управления, если имя элемента управления написано с ошибкой ("TeStBox2"
). В таких случаяхNothing
они снова будут храниться в этих элементах массива, и при попытке ссылки на него будет получено NRE.Теперь их легко найти, когда вы знаете, что ищете:
"Button2" находится на
Panel
средство
Вместо косвенных ссылок по имени с использованием
Controls
коллекции формы используйте контрольную ссылку:Функция ничего не возвращает
Это тот случай, когда IDE предупредит вас, что « не все пути возвращают значение и
NullReferenceException
может привести к результату ». Вы можете подавить предупреждение, заменивExit Function
сReturn Nothing
, но это не решает проблему. Все, что пытается использовать возвращение, когдаsomeCondition = False
приведет к NRE:средство
Заменить
Exit Function
в функции наReturn bList
. Возврат пустогоList
не означает возвращениеNothing
. Если есть вероятность, что возвращенный объект может бытьNothing
, протестируйте перед его использованием:Плохо реализовано Try / Catch
Плохо реализованный Try / Catch может скрыть, где проблема, и привести к новым:
Это случай, когда объект создается не так, как ожидалось, но также демонстрирует полезность счетчика пустого
Catch
.В SQL есть дополнительная запятая (после 'mailaddress'), что приводит к исключению в
.ExecuteReader
. После того,Catch
как ничего не делает,Finally
пытается выполнить очистку, но, поскольку вы не можетеClose
нулевойDataReader
объект, совершенно новыйNullReferenceException
результат.Пустой
Catch
блок - игровая площадка дьявола. Этот ОП был сбит с толку, почему он получил NRE вFinally
блоке. В других ситуациях пустое состояниеCatch
может привести к тому, что что-то еще ниже по течению станет бесполезным, и вы потратите время на поиск неправильных вещей в неподходящем месте для решения проблемы. (Описанное выше «тихое исключение» обеспечивает ту же развлекательную ценность.)средство
Не используйте пустые блоки Try / Catch - позвольте коду аварийно завершить работу, чтобы вы могли a) определить причину b) определить местоположение и c) применить надлежащее решение. Блоки Try / Catch не предназначены для сокрытия исключений от лица, обладающего уникальной квалификацией для их устранения - разработчика.
DBNull не то же самое, что Nothing
IsDBNull
Функция используется для проверки , если значение равноSystem.DBNull
: Из MSDN:средство
Как и раньше, вы можете проверить на Ничто, а затем для конкретного значения:
Пример 2
FirstOrDefault
возвращает первый элемент или значение по умолчанию, которое предназначеноNothing
для ссылочных типов и никогдаDBNull
:управления
Если
CheckBox
сchkName
не может быть найдено (или существует вGroupBox
), тоchk
будет Nothing, и попытка ссылки на какое-либо свойство приведет к исключению.средство
DataGridView
У DGV есть несколько причуд, периодически замечаемых:
Если
dgvBooks
имеетAutoGenerateColumns = True
, он будет создавать столбцы, но он не называет их, поэтому приведенный выше код завершается ошибкой, когда он ссылается на них по имени.средство
Назовите столбцы вручную или используйте указатель по индексу:
Пример 2 - Остерегайтесь NewRow
Когда у вас
DataGridView
естьAllowUserToAddRows
asTrue
(по умолчанию),Cells
в пустой / новой строке внизу все будет содержатьNothing
. Большинство попыток использовать содержимое (например,ToString
) приведет к NRE.средство
Используйте
For/Each
цикл и протестируйтеIsNewRow
свойство, чтобы определить, последняя ли это строка. Это работает независимо от тогоAllowUserToAddRows
, верно это или нет:Если вы используете
For n
цикл, изменять количество строк или использовать ,Exit For
когдаIsNewRow
это верно.My.Settings (StringCollection)
При определенных обстоятельствах попытка использовать элемент из
My.Settings
которогоStringCollection
может привести к NullReference при первом его использовании. Решение то же самое, но не так очевидно. Рассматривать:Поскольку VB управляет настройками для вас, разумно ожидать, что он инициализирует коллекцию. Это произойдет, но только если вы ранее добавили начальную запись в коллекцию (в редакторе настроек). Поскольку коллекция (по-видимому) инициализируется при добавлении элемента, она остается,
Nothing
когда в редакторе настроек нет элементов для добавления.средство
Инициализируйте коллекцию настроек в
Load
обработчике событий формы, если / когда это необходимо:Как правило,
Settings
коллекция должна быть инициализирована только при первом запуске приложения. Альтернативное решение - добавить начальное значение в вашу коллекцию в Project -> Settings | FooBars , сохраните проект, затем удалите поддельное значение.Ключевые моменты
Вы, наверное, забыли
New
оператора.или
То, что вы предполагали, будет работать безупречно, чтобы вернуть инициализированный объект в ваш код, не так.
Не игнорируйте предупреждения компилятора (всегда) и используйте
Option Strict On
(всегда).MSDN NullReference Исключение
источник
Другой сценарий - когда вы приводите нулевой объект в тип значения . Например, код ниже:
Это бросит
NullReferenceException
на бросок. Это кажется вполне очевидным в приведенном выше примере, но это может произойти в более сложных запоздалых сценариях, когда нулевой объект был возвращен из некоторого кода, который вам не принадлежит, и приведение, например, генерируется некоторой автоматической системой.Одним из примеров этого является этот простой фрагмент привязки ASP.NET с элементом управления Calendar:
Здесь,
SelectedDate
на самом деле, это свойство -DateTime
типа - типаCalendar
Web Control, и привязка может совершенно вернуть что-то нулевое. Неявный ASP.NET Generator создаст кусок кода, который будет эквивалентен приведенному выше коду. И это вызоветNullReferenceException
довольно трудную задачу, потому что он лежит в сгенерированном ASP.NET коде, который прекрасно компилируется ...источник
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Это означает, что рассматриваемая переменная ни на что не указывает. Я мог бы сгенерировать это так:
Это выдаст ошибку, потому что, хотя я объявил переменную "
connection
", она ни на что не указана. Когда я пытаюсь вызвать участника "Open
", нет ссылки для его разрешения, и он выдаст ошибку.Чтобы избежать этой ошибки:
object == null
.Инструмент JetBrains Resharper будет идентифицировать каждое место в вашем коде, в котором может быть ошибка нулевой ссылки, что позволяет вам поставить нулевую проверку. Эта ошибка - источник ошибок номер один, ИМХО.
источник
Это означает, что ваш код использовал переменную ссылки на объект, для которой было установлено значение null (то есть он не ссылался на фактический экземпляр объекта).
Чтобы предотвратить ошибку, объекты, которые могут иметь значение NULL, должны быть проверены на NULL перед использованием.
источник
Имейте в виду, что независимо от сценария, причина всегда одинакова в .NET:
источник
Пример этого исключения: Когда вы пытаетесь что-то проверить, это пустое значение.
Например:
Среда выполнения .NET генерирует исключение NullReferenceException при попытке выполнить действие с чем-то, что не было создано, например с кодом выше.
По сравнению с ArgumentNullException, который обычно генерируется как защитная мера, если метод ожидает, что то, что ему передается, не равно нулю.
Больше информации в C # NullReferenceException и Null Parameter .
источник
Обновление C # 8.0, 2019: Обнуляемые ссылочные типы
C # 8.0 вводит пустые ссылочные типы и ненулевые ссылочные типы . Поэтому необходимо проверять только обнуляемые ссылочные типы, чтобы избежать исключения NullReferenceException .
Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, оно выдаст исключение NullReferenceException .
Пример:
Вы можете просто избежать этого, проверив, не является ли переменная нулевой:
Чтобы полностью понять, почему выбрасывается исключение NullReferenceException, важно знать разницу между типами значений и [ссылочными типами] [3].
Итак, если вы имеете дело с типами значений , NullReferenceExceptions не может возникнуть. Хотя при работе с ссылочными типами нужно соблюдать бдительность !
Только ссылочные типы, как следует из названия, могут содержать ссылки или указывать буквально на ничто (или «ноль»). В то время как типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
Типы значений (вы можете просто игнорировать эти):
источник
Еще один случай, когда
NullReferenceExceptions
может произойти (неправильное) использованиеas
оператора :Вот,
Book
иCar
есть несовместимые типы; аCar
не может быть преобразован / приведен кBook
. Когда это приведение не удается,as
возвращаетсяnull
. Использованиеmybook
после этого вызываетNullReferenceException
.В общем, вы должны использовать приведение или
as
, как показано ниже:Если вы ожидаете, что преобразование типов будет всегда успешным (т.е. вы знаете, какой объект должен быть раньше времени), тогда вам следует использовать приведение:
Если вы не уверены в типе, но хотите попробовать использовать его как определенный тип, используйте
as
:источник
Вы используете объект, который содержит ссылку на нулевое значение. Так что это дает нулевое исключение. В этом примере строковое значение равно нулю, и при проверке его длины произошло исключение.
Пример:
Ошибка исключения:
источник
В то время как то, что вызывает исключения NullReferenceException и подходы, чтобы избежать / исправить такое исключение, было рассмотрено в других ответах, многие программисты еще не узнали, как самостоятельно отлаживать такие исключения во время разработки.
В Visual Studio это обычно легко благодаря отладчику Visual Studio .
Во-первых, убедитесь, что будет обнаружена правильная ошибка - см. Как разрешить разрыв на System.NullReferenceException в VS2010? Примечание 1
Затем либо начните с отладки (F5), либо присоедините [отладчик VS] к запущенному процессу . В некоторых случаях это может быть полезно для использования
Debugger.Break
, который предложит запустить отладчик.Теперь, когда NullReferenceException генерируется (или не обрабатывается), отладчик останавливается (помните, как установлено выше?) На строке, в которой произошло исключение. Иногда ошибку легко заметить.
Например, в следующей строке единственным кодом, который может вызвать исключение, является
myString
значение null. Это можно проверить, посмотрев в окно просмотра или запустив выражения в Immediate Window .В более сложных случаях, таких как следующие, вам нужно использовать один из методов, описанных выше (Watch или Immediate Windows), чтобы проверить выражения, чтобы определить, было ли
str1
NULL илиstr2
NULL.После того, когда исключение составляет бросок был расположен, обычно тривиальной причине задом наперед , чтобы выяснить , где нулевое значение было [неправильно] ввел -
Потратьте время, необходимое для понимания причины исключения. Осмотрите для нулевых выражений. Проверьте предыдущие выражения, которые могли привести к таким нулевым выражениям. Добавьте точки останова и пошагово пройдитесь по программе. Используйте отладчик.
1 Если Break on Throws слишком агрессивен и отладчик останавливается на NPE в .NET или сторонней библиотеке, можно использовать Break on User-Unhandled для ограничения перехвата исключений. Кроме того, VS2012 представляет Just My Code, который я также рекомендую включить.
источник
Саймон Мурье привел этот пример :
где преобразование распаковки (приведение) из
object
(или из одного из классовSystem.ValueType
илиSystem.Enum
, или из типа интерфейса) в тип значения (отличный отNullable<>
) само по себе даетNullReferenceException
.В другом направлении, A бокс преобразование из
Nullable<>
который имеетHasValue
равныйfalse
к ссылочному типу, может датьnull
ссылку , которая затем может впоследствии привести кNullReferenceException
. Классический пример:Иногда бокс бывает по-другому. Например, с помощью этого неуниверсального метода расширения:
следующий код будет проблематичным:
Эти случаи возникают из-за специальных правил, которые среда выполнения использует при создании
Nullable<>
экземпляров.источник
Добавление случая, когда имя класса для сущности, используемой в платформе сущностей, совпадает с именем класса для файла кода веб-формы.
Предположим, у вас есть веб-форма Contact.aspx, класс codebehind которой - «Контакт», и у вас есть имя сущности «Контакт».
Затем следующий код вызовет исключение NullReferenceException при вызове context.SaveChanges ()
Ради полноты класса DataContext
и Связаться с объектом класса. Иногда классы сущностей являются частичными классами, так что вы можете расширять их и в других файлах.
Ошибка возникает, когда сущность и класс codebehind находятся в одном пространстве имен. Чтобы исправить это, переименуйте класс сущности или класс codebehind для Contact.aspx.
причина я все еще не уверен в причине. Но всякий раз, когда какой-либо из классов сущностей расширяет System.Web.UI.Page, эта ошибка возникает.
Для обсуждения взгляните на NullReferenceException в DbContext.saveChanges ()
источник
Другой общий случай, когда можно получить это исключение, связан с классами насмешек во время модульного тестирования. Независимо от используемой среды моделирования, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом смоделированы. В частности, все свойства, на
HttpContext
которые ссылается тестируемый код, должны быть проверены.См. « NullReferenceException, генерируемое при тестировании пользовательского AuthorizationAttribute » для несколько подробного примера.
источник
У меня другая точка зрения, чтобы ответить на это. Такого рода ответы "что еще я могу сделать, чтобы избежать этого? "
При работе на разных уровнях , например, в приложении MVC, контроллеру нужны сервисы для вызова бизнес-операций. В таких сценариях Dependency Injection Container можно использовать для инициализации служб, чтобы избежать исключения NullReferenceException . Таким образом, это означает, что вам не нужно беспокоиться о проверке на null и просто вызывать сервисы из контроллера, как если бы они всегда были доступны (и инициализированы) в виде одиночного или прототипа.
источник
На вопрос «что мне с этим делать» может быть много ответов.
Более «формальным» способом предотвращения возникновения таких ошибок при разработке является применение проекта по контракту в вашем коде. Это означает, что вам нужно установить инварианты класса и / или даже предварительные условия и постфункции в вашей системе при разработке.
Короче говоря, инварианты класса гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушаться при обычном использовании (и, следовательно, класс не попадет в противоречивое состояние). Предварительные условия означают, что данные, переданные в качестве входных данных для функции / метода, должны соответствовать некоторым установленным ограничениям и никогда не нарушать их, а постусловия означают, что выходные данные функции / метода должны снова следовать установленным ограничениям, не нарушая их. Условия контракта никогда не должны нарушаться во время выполнения безошибочной программы, поэтому проектирование по контракту проверяется на практике в режиме отладки, хотя и отключается в выпусках , чтобы максимизировать производительность разработанной системы.
Таким образом, вы можете избежать
NullReferenceException
случаев, которые являются результатом нарушения установленных ограничений. Например, если вы используете свойство объектаX
в классе, а затем пытаетесь вызвать один из его методов иX
имеет нулевое значение, то это приведет кNullReferenceException
:Но если вы установите «свойство X никогда не должно иметь нулевое значение» в качестве предварительного условия метода, то вы можете предотвратить описанный выше сценарий:
По этой причине проект Code Contracts существует для приложений .NET.
В качестве альтернативы, дизайн по контракту может быть применен с использованием утверждений .
ОБНОВЛЕНИЕ: Стоит отметить, что этот термин был придуман Бертраном Мейером в связи с его разработкой языка программирования Eiffel .
источник
A
NullReferenceException
выдается, когда мы пытаемся получить доступ к свойствам нулевого объекта или когда строковое значение становится пустым, а мы пытаемся получить доступ к строковым методам.Например:
При обращении к строковому методу пустой строки:
При обращении к свойству нулевого объекта:
источник
String.Empty.ToLower()
не сгенерирует исключение нулевой ссылки. Он представляет фактическую строку, хотя и пустую (то есть""
). Так как здесь есть объект для вызоваToLower()
, не имеет смысла бросать туда исключение нулевой ссылки.TL; DR: попробуйте использовать
Html.Partial
вместоRenderpage
Я получал,
Object reference not set to an instance of an object
когда пытался визуализировать представление в представлении, отправив ему модель, например так:Отладка показала, что модель была нулевой внутри MyOtherView. Пока я не изменил это на:
И это сработало.
Кроме того, причина, по которой мне не нужно
Html.Partial
было начинать, заключалась в том, что Visual Studio иногда бросает волнистые строки, выглядящие как ошибки,Html.Partial
если он находится внутриforeach
цикла, построенного по-другому , даже если это на самом деле не ошибка:Но я смог запустить приложение без проблем с этой «ошибкой». Я смог избавиться от ошибки, изменив структуру
foreach
цикла так:Хотя у меня такое ощущение, что Visual Studio неправильно читала амперсанды и скобки.
источник
Html.Partial
, не@Html.Partial
Null
), поэтому я знал, что ошибка была в том, как я отправлял Модель.Что вы можете с этим поделать?
Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но есть очень мало о том, как предотвратить проблему или, по крайней мере, облегчить ее обнаружение.
Проверьте аргументы
Например, методы могут проверять различные аргументы, чтобы определить
ArgumentNullException
, являются ли они пустыми, и выдавать исключение, явно созданное для этой конкретной цели.Конструктор для
ArgumentNullException
even принимает имя параметра и сообщение в качестве аргумента, чтобы вы могли точно сказать разработчику, в чем заключается проблема.Используйте инструменты
Есть также несколько библиотек, которые могут помочь. Например, «Resharper» может выдавать вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute
Есть «Microsoft Code Contracts», где вы используете синтаксис, подобный тому,
Contract.Requires(obj != null)
который дает вам время выполнения и проверку компиляции: Введение в Code Contracts .Также есть «PostSharp», который позволит вам просто использовать такие атрибуты:
Сделав это и сделав PostSharp частью вашего процесса сборки,
obj
вы будете проверяться на ноль во время выполнения. Смотрите: PostSharp нулевая проверкаРешение с простым кодом
Или вы всегда можете написать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать для перехвата нулевых ссылок. Он смоделирован по той же концепции, что и
Nullable<T>
:Вы будете использовать очень похоже на то же самое, что и вы
Nullable<T>
, за исключением того, что вы делаете совершенно противоположное - не допуститьnull
. Вот некоторые примеры:NotNull<T>
неявно приведен к и от,T
так что вы можете использовать его где угодно. Например, вы можете передатьPerson
объект в метод, который принимаетNotNull<Person>
:Как вы можете видеть выше, как с nullable, вы получите доступ к базовому значению через
Value
свойство. Кроме того, вы можете использовать явное или неявное приведение, вы можете увидеть пример с возвращаемым значением ниже:Или вы можете даже использовать его, когда метод просто возвращает
T
(в данном случаеPerson
), выполняя приведение. Например, следующий код будет похож на код выше:Объединить с расширением
Объедините
NotNull<T>
с методом расширения, и вы сможете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:И вот пример того, как это можно использовать:
GitHub
Для справки, я сделал приведенный выше код доступным на GitHub, вы можете найти его по адресу:
https://github.com/luisperezphd/NotNull
Родственный язык
В C # 6.0 введен «нулевой оператор», который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты и, если какой-либо из них является
null
целым выражением, возвращаетсяnull
.Это уменьшает количество нулевых проверок, которые вы должны сделать в некоторых случаях. Синтаксис ставит знак вопроса перед каждой точкой. Возьмите следующий код для примера:
Представьте, что
country
это объект типаCountry
, у которого есть свойство с именемState
и так далее. Еслиcountry
,State
,County
илиCity
этоnull
тоaddress will be
нулевой. Therefore you only have to check whether
адресis
null`.Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.
Встроенный как Nullable?
В C # есть хорошее обозначение:
Nullable<T>
вы можете сделать что-то обнуляемое, поставив знак вопроса после такого типаint?
.Было бы хорошо , если бы C # было что - то вроде
NotNull<T>
структуры выше и имел подобную стенографии, может быть восклицательным знаком , так что вы могли бы написать что - то вроде (!)public void WriteName(Person! person)
.источник
Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я добавлю их:
Крайний случай № 1: одновременный доступ к словарю
Общие словари в .NET не являются поточно-ориентированными и иногда могут выдавать
NullReference
или даже (чаще)KeyNotFoundException
при попытке получить доступ к ключу из двух параллельных потоков. Исключение весьма обманчиво в этом случае.Крайний случай № 2: небезопасный код
Если a
NullReferenceException
генерируетсяunsafe
кодом, вы можете посмотреть на переменные-указатели и проверить их на наличиеIntPtr.Zero
чего-либо. Это то же самое («исключение нулевого указателя»), но в небезопасном коде переменные часто приводятся к типам значений / массивам и т. Д., И вы бьетесь головой о стену, задаваясь вопросом, как тип значения может бросить это исключение.(Кстати, еще одна причина не использовать небезопасный код, если он вам не нужен)
источник
null
чем?Вы можете исправить NullReferenceException чистым способом с помощью Null-условных операторов в c # 6 и написать меньше кода для обработки нулевых проверок.
Он используется для проверки на нулевое значение перед выполнением операции доступа к члену (?.) Или индекса (? [).
пример
эквивалентно:
В результате имя будет нулевым, когда p равно нулю или когда p.Spouse равно нулю.
В противном случае имени переменной будет присвоено значение p.Spouse.FirstName.
Для более подробной информации: Нулевые операторы
источник
Строка ошибки «Ссылка на объект не установлена для экземпляра объекта.» Гласит, что вы не назначили объект экземпляра для ссылки на объект, и все же вы получаете доступ к свойствам / методам этого объекта.
например: допустим, у вас есть класс с именем myClass, и он содержит одно свойство prop1.
Теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:
вышеприведенная строка выдает ошибку, поскольку ссылка на класс myClass объявлена, но не создана, или экземпляр объекта не назначен для ссылки на этот класс.
Чтобы это исправить, вы должны создать экземпляр (назначить объект для ссылки на этот класс).
источник
NullReferenceException или ссылка на объект, не установленная для экземпляра объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:
Предположим, что у вас есть класс с именем Student.
Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.
Как видно из приведенного выше кода, оператор Student s - только объявляет переменную типа Student, обратите внимание, что на этом этапе класс Student не создается. Следовательно, когда выполняется оператор s.GetFullName () , он генерирует исключение NullReferenceException.
источник
Ну, простыми словами:
Вы пытаетесь получить доступ к объекту, который не создан или в данный момент отсутствует в памяти.
Итак, как справиться с этим:
Отладьте и дайте отладчику сломаться ... Он напрямую приведет вас к сломанной переменной ... Теперь ваша задача просто исправить это ... Используя ключевое слово new в соответствующем месте.
Если это вызвано в некоторых командах базы данных, потому что объект не присутствует, тогда все, что вам нужно сделать, это сделать нулевую проверку и обработать ее:
Сложнее всего ... если GC уже собрал объект ... Обычно это происходит, если вы пытаетесь найти объект с помощью строк ... То есть, находя его по имени объекта, может случиться так, что GC может уже Вычистил это ... Это трудно найти и станет большой проблемой ... Лучший способ справиться с этим - делать нулевые проверки везде, где это необходимо в процессе разработки. Это сэкономит вам много времени.
Под поиском по имени я подразумеваю некоторую инфраструктуру, позволяющую вам FIndObjects использовать строки, и код может выглядеть следующим образом: FindObject ("ObjectName");
источник
Буквально самый простой способ исправить NullReferenceExeption имеет два способа. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (hardbody), эта переменная будет начинаться с нуля, когда вы начнете свою игру.
Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.
Я буду использовать переменную RigidBody в качестве примера.
Мы можем действительно легко добавить данные несколькими способами:
Затем перейдите в свой сценарий и введите.
rb = GetComponent<Rigidbody>();
Эта строка кода лучше всего работает под вашим
Start()
илиAwake()
функциями.rb = AddComponent<RigidBody>();
Дополнительные примечания: Если вы хотите, чтобы Unity добавила компонент к вашему объекту, и, возможно, вы забыли добавить его, вы можете напечатать
[RequireComponent(typeof(RigidBody))]
над объявлением класса (пробел под всеми вашими использованиями).Наслаждайтесь игрой и получайте удовольствие!
источник
Если мы рассмотрим распространенные сценарии, в которых это исключение может быть выброшено, доступ к свойствам осуществляется с помощью объекта сверху.
Пример:
здесь, если адрес равен нулю, то вы получите NullReferenceException.
Таким образом, в качестве практики мы всегда должны использовать проверку null, прежде чем обращаться к свойствам в таких объектах (особенно в общем)
источник
Это в основном является нулевым ссылочным исключением . Как заявляет Microsoft,
Что это обозначает?
Это означает, что если какой-либо участник, который не имеет никакого значения, и мы заставляем этого участника выполнять определенную задачу, то система, несомненно, бросит сообщение и скажет:
«Эй, подождите, у этого члена нет значений, поэтому он не может выполнить задачу, которую вы передаете».
Само исключение говорит, что на что-то ссылаются, но чье значение не устанавливается. Таким образом, это означает, что это происходит только при использовании ссылочных типов, поскольку типы значений не могут быть обнуляемыми.
NullReferenceException не произойдет, если мы используем члены типа Value.
Приведенный выше код показывает простую строку, которой присваивается нулевое значение.
Теперь, когда я пытаюсь напечатать длину строки str , я получаю сообщение о необработанном исключении типа «System.NullReferenceException», потому что член str указывает на ноль и не может быть никакой длины ноль.
« NullReferenceException » также происходит , когда мы забываем экземпляр ссылочного типа.
Предположим, у меня есть метод класса и члена. Я не создал экземпляр своего класса, а только назвал свой класс. Теперь, если я попытаюсь использовать метод, компилятор выдаст ошибку или выдаст предупреждение (в зависимости от компилятора).
Компилятор для приведенного выше кода выдает ошибку, что переменная obj не назначена, что означает, что наша переменная имеет нулевые значения или ничего. Компилятор для приведенного выше кода выдает ошибку, что переменная obj не назначена, что означает, что наша переменная имеет нулевые значения или ничего.
Почему это происходит?
NullReferenceException возникает из-за нашей ошибки в том, что мы не проверили значение объекта. Мы часто оставляем значения объектов непроверенными в разработке кода.
Это также возникает, когда мы забываем создавать экземпляры наших объектов. Использование методов, свойств, коллекций и т. Д., Которые могут возвращать или устанавливать нулевые значения, также может быть причиной этого исключения.
Как этого можно избежать?
Существуют различные способы и способы избежать этого известного исключения:
Явная проверка. Мы должны придерживаться традиции проверки объектов, свойств, методов, массивов и коллекций на предмет наличия нулевых значений. Это может быть просто реализовано с использованием условных операторов, таких как if-else, if-else и т. Д.
Обработка исключений: один из важных способов управления этим исключением. Используя простые блоки try-catch-finally, мы можем контролировать это исключение, а также вести его журнал. Это может быть очень полезно, когда ваше приложение находится на стадии разработки.
Нулевые операторы: нулевой оператор слияния и нулевые условные операторы также могут быть полезны при задании значений для объектов, переменных, свойств и полей.
Отладчик: Для разработчиков у нас есть большое оружие отладки. Если мы столкнулись с NullReferenceException во время разработки, мы можем использовать отладчик, чтобы добраться до источника исключения.
Встроенный метод. Системные методы, такие как GetValueOrDefault (), IsNullOrWhiteSpace () и IsNullorEmpty (), проверяют наличие нулевых значений и присваивают значение по умолчанию, если существует нулевое значение.
Здесь уже есть много хороших ответов. Вы также можете проверить более подробное описание с примерами в моем блоге .
Надеюсь, это тоже поможет!
источник
Если вы получаете это сообщение во время сохранения или компиляции сборки, просто закройте все файлы и затем откройте любой файл для компиляции и сохранения.
Для меня причина была в том, что я переименовал файл, а старый файл все еще был открыт.
источник