что такое исключение nullreferenceexception и как его исправить?

<p>у меня есть некоторый код, и когда он выполняется, он выдает <code>nullreferenceexception</code>, говоря:</p><blockquote> <p>в экземпляре объекта не задана ссылка на объект.</p> </blockquote><p>что это значит, и что я могу сделать, чтобы исправить эту ошибку?</p>

<h1>исключение nullreference - visual basic</h1><p><code>nullreference exception</code> для <strong> visual basic </strong> не отличается от кода в <strong> c # </strong>. в конце концов, они оба сообщают об одном и том же исключении, определенном в .net framework, которое они оба используют. причины, уникальные для visual basic, встречаются редко (возможно, только одна).</p><p>в этом ответе будут использоваться термины, синтаксис и контекст visual basic. используемые примеры взяты из большого количества прошлых вопросов о переполнении стека. это делается для максимизации релевантности с помощью <em> видов </em> ситуаций, часто встречающихся в постах. немного больше объяснений также предоставляется тем, кому это может понадобиться. пример, похожий на ваш, <em> очень </em>, скорее всего, приведен здесь.</p><p><strong> примечание: </strong></p><ol> <li>это основано на концепции: нет кода для вставки в ваш проект. он предназначен для того, чтобы помочь вам понять, что вызывает <code>nullreferenceexception</code>(nre), как его найти, как исправить и как его избежать. nre может быть вызвано многими способами, так что вряд ли это будет ваша единственная встреча.</li> <li>примеры (из сообщений stack overflow) не всегда показывают лучший способ сделать что-либо в первую очередь.</li> <li>как правило, самое простое средство используется.</li> </ol><h2>основное значение</h2><p>сообщение <em> "объект не установлен в экземпляр объекта" </em> означает, что вы пытаетесь использовать объект, который не был инициализирован. это сводится к одному из них:</p><ul> <li>ваш код <em> объявил </em> переменную объекта, но он не <em> инициализировал </em> ее (создал экземпляр или '<em> создать экземпляр </em> 'это)</li> <li>то, что ваш код предполагал инициализировать объект, не</li> <li>возможно, другой код преждевременно лишил законной силы объект, все еще используемый</li> </ul><h2>в поисках причины</h2><p>поскольку проблема заключается в ссылке на объект <code>nothing</code>name\_\_, ответ состоит в том, чтобы изучить их, чтобы выяснить, какая из них. затем определите, почему он не инициализирован. наведите указатель мыши на различные переменные, и visual studio (vs) покажет их значения - виновником будет <code>nothing</code>name\_\_.</p><p><img src="https://i.stack.imgur.com/5ndsa.jpg" alt="ide debug display"></p><p>вам также следует удалить все блоки try/catch из соответствующего кода, особенно те, в которых нет ничего в блоке catch. это приведет к сбою вашего кода при попытке использовать объект <code>nothing</code>name\_\_. <strong> это то, что вы хотите </strong>, потому что он определит точное <em> местоположение </em> проблемы и позволит вам определить объект, вызывающий его.</p><p><code>msgbox</code>в catch, который отображает <code>error while...</code>, мало поможет. этот метод также приводит к <em> очень плохим </em> вопросам переполнения стека, потому что вы не можете описать фактическое исключение, задействованный объект или даже строку кода, где это происходит.</p><p>вы также можете использовать <code>locals window</code> (<strong> debug -> windows -> locals </strong>) для проверки ваших объектов.</p><p>после того, как вы знаете, в чем и где проблема, ее обычно довольно легко исправить и быстрее, чем опубликовать новый вопрос.</p><p>смотрите также:</p><ul> <li> <a href="https://msdn.microsoft.com/en-us/library/ktf38f66.aspx">контрольные точки</a> </li> <li> <a href="http://msdn.microsoft.com/en-us/library/xtd0s8kd(v=vs.110).aspx">msdn: как: использовать блок try/catch для отлова исключений</a> </li> <li> <a href="http://msdn.microsoft.com/en-us/library/seyhszts(v=vs.110).aspx">msdn: лучшие практики для исключений</a> </li> </ul><h2>примеры и средства правовой защиты</h2><h2>объекты класса/создание экземпляра</h2><pre class="lang-vb prettyprint-override"><code>dim reg as cashregister ... textbox1.text = reg.amount ' nre </code></pre><p>проблема в том, что <code>dim</code>не создает объект cashregister <em> </em>; он только объявляет переменную с именем <code>reg</code>этого типа. <em> объявление </em> переменной объекта и создание экземпляра <em> </em> - это две разные вещи.</p><p><strong> remedy </strong></p><p>оператор <code>new</code>часто можно использовать для создания экземпляра при его объявлении:</p><pre class="lang-vb prettyprint-override"><code>dim reg as new cashregister ' [new] creates instance, invokes the constructor ' longer, more explicit form: dim reg as cashregister = new cashregister </code></pre><p>когда уместно создать экземпляр позже:</p><pre class="lang-vb prettyprint-override"><code>private reg as cashregister ' declare ... reg = new cashregister() ' create instance </code></pre><p>примечание: <strong> не </strong> снова используйте <code>dim</code>в процедуре, включая конструктор (<code>sub new</code>):</p><pre class="lang-vb prettyprint-override"><code>private reg as cashregister '... public sub new() '... dim reg as new cashregister end sub </code></pre><p>это создаст <em> локальную </em> переменную <code>reg</code>name\_\_, которая существует только в этом контексте (подпункте). переменная <code>reg</code>с уровнем модуля <code>scope</code>name\_\_, которую вы будете использовать везде, остается <code>nothing</code>name\_\_.</p><blockquote> <p><strong> отсутствие оператора <code>new</code>является # 1 причиной <code>nullreference exceptions</code> </strong>, замеченной в рассмотренных вопросах переполнения стека.</p> <p>visual basic несколько раз пытается сделать процесс очистки понятным, используя <strong><code>new</code>name \_</strong>: используя <strong><code>new</code>name \_</strong> оператор создает <strong> новый </strong> объект и вызывает <strong><code>sub new</code></strong> - конструктор - - где ваш объект может выполнить любую другую инициализацию.</p> </blockquote><p>для ясности, только <code>dim</code>(или <code>private</code>name\_\_) <em> объявляет </em> переменную и ее <code>type</code>name\_\_. область <em> </em> переменной - существует ли она для всего модуля/класса или является локальной для процедуры - определяется как <em> где </em> это объявлено. <code>private | friend | public</code> определяет уровень доступа, а не <em> область </em>.</p><p>для получения дополнительной информации см .:</p><ul> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/new-operator">новый оператор</a> </li> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/scope">область применения в visual basic</a> </li> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/access-levels">уровни доступа в visual basic</a> </li> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/value-types-and-reference-types">типы значений и ссылочные типы</a> </li> </ul><hr><h2>массивы</h2><p>массивы также должны быть созданы:</p><pre class="lang-vb prettyprint-override"><code>private arr as string() </code></pre><p>этот массив только объявлен, но не создан. существует несколько способов инициализации массива:</p><pre class="lang-vb prettyprint-override"><code>private arr as string() = new string(10){} ' or private arr() as string = new string(10){} ' for a local array (in a procedure) and using 'option infer': dim arr = new string(10) {} </code></pre><p>примечание. начиная с vs 2010, при инициализации локального массива с использованием литерала и <code>option infer</code> элементы <code>as <type></code> и <code>new</code>являются необязательными:</p><pre class="lang-vb prettyprint-override"><code>dim mydbl as double() = {1.5, 2, 9.9, 18, 3.14} dim mydbl = new double() {1.5, 2, 9.9, 18, 3.14} dim mydbl() = {1.5, 2, 9.9, 18, 3.14} </code></pre><p>тип данных и размер массива выводятся из назначаемых данных. для объявлений уровня класса/модуля все еще требуется <code>as <type></code> с <code>option strict</code>:</p><pre class="lang-vb prettyprint-override"><code>private mydoubles as double() = {1.5, 2, 9.9, 18, 3.14} </code></pre><p><strong> пример: массив объектов класса </strong></p><pre class="lang-vb prettyprint-override"><code>dim arrfoo(5) as foo for i as integer = 0 to arrfoo.count - 1 arrfoo(i).bar = i * 10 ' exception next </code></pre><p>массив создан, а объекты <code>foo</code>в нем - нет.</p><p><strong> remedy </strong></p><pre class="lang-vb prettyprint-override"><code>for i as integer = 0 to arrfoo.count - 1 arrfoo(i) = new foo() ' create foo instance arrfoo(i).bar = i * 10 next </code></pre><p>использование функции <code>list(of t)</code> весьма затруднит получение элемента без действительного объекта:</p><pre class="lang-vb prettyprint-override"><code>dim foolist as new list(of foo) ' list created, but it is empty dim f as foo ' temporary variable for the loop for i as integer = 0 to 5 f = new foo() ' foo instance created f.bar = i * 10 foolist.add(f) ' foo object added to list next </code></pre><p>для получения дополнительной информации см .:</p><ul> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/option-infer-statement">опция infer statement</a> </li> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/scope">область применения в visual basic</a> </li> <li> <a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/arrays/index">массивы в visual basic</a> </li> </ul><hr><h2>списки и коллекции</h2><p>коллекции .net (которых существует много разновидностей - списки, словарь и т.д.) также должны быть созданы или созданы.</p><pre class="lang-vb prettyprint-override"><code>private mylist as list(of string) .. mylist.add("ziggy") ' nullreference </code></pre><p>вы получаете то же исключение по той же причине - <code>mylist</code>был только объявлен, но экземпляр не создан. средство защиты такое же:</p><pre class="lang-vb prettyprint-override"><code>mylist = new list(of string) ' or create an instance when declared: private mylist as new list(of string) </code></pre><p>обычный недосмотр - это класс, который использует коллекцию <code>type</code>name\_\_:</p><pre class="lang-vb prettyprint-override"><code>public class foo private barlist as list(of bar) friend function barcount as integer return barlist.count end function friend sub additem(newbar as bar) if barlist.contains(newbar) = false then barlist.add(newbar) end if end function </code></pre><p>любая процедура приведет к nre, потому что <code>barlist</code>только объявлен, но не создан. создание экземпляра <code>foo</code>также не создаст экземпляр внутреннего <code>barlist</code>name\_\_. возможно, это было сделано в конструкторе:</p><pre class="lang-vb prettyprint-override"><code>public sub new ' constructor ' stuff to do when a new foo is created... barlist = new list(of bar) end sub </code></pre><p>как и раньше, это неверно:</p><pre class="lang-vb prettyprint-override"><code>public sub new() ' creates another barlist local to this procedure dim barlist as new list(of bar) end sub </code></pre><p>для получения дополнительной информации см. <a href="https://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx"><code>list(of t)</code> class</a> .</p><hr><h2>объекты провайдера данных</h2><p>работа с базами данных предоставляет множество возможностей для nullreference, поскольку одновременно может использоваться несколько объектов (<code>command</code>name\_\_, <code>connection</code>name\_\_, <code>transaction</code>name\_\_, <code>dataset</code>name\_\_, <code>datatable</code>name\_\_, <code>datarows</code>name \_\_....). <strong> примечание: </strong> неважно, какой поставщик данных вы используете - mysql, sql server, oledb и т.д. - <em> понятия </em> одинаковы.</p><p><strong> пример 1 </strong></p><pre class="lang-vb prettyprint-override"><code>dim da as oledbdataadapter dim ds as dataset dim maxrows as integer 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 </code></pre><p>как и раньше, объект набора данных <code>ds</code>был объявлен, но экземпляр так и не был создан. <code>dataadapter</code>заполнит существующее <code>dataset</code>name\_\_, а не создаст его. в этом случае, поскольку <code>ds</code>является локальной переменной, <em> ide предупреждает вас </em>, что это может произойти:</p><p><img src="https://i.stack.imgur.com/e5d94.jpg" alt="img"></p><p>когда объявлено как переменная уровня модуля/класса, как это имеет место с <code>con</code>name\_\_, компилятор не может знать, был ли объект создан процедурой выше по потоку. не игнорируйте предупреждения.</p><p><strong> remedy </strong></p><pre class="lang-vb prettyprint-override"><code>dim ds as new dataset </code></pre><p><strong> пример 2 </strong></p><pre class="lang-vb prettyprint-override"><code>ds = new dataset da = new oledbdataadapter(sql, con) da.fill(ds, "employees") txtid.text = ds.tables("employee").rows(0).item(1) txtid.name = ds.tables("employee").rows(0).item(2) </code></pre><p>опечатка - проблема здесь: <code>employees</code>vs <code>employee</code>name\_\_. не было создано <code>datatable</code>с именем "employee", поэтому <code>nullreferenceexception</code>пытается получить к нему доступ. другая потенциальная проблема заключается в предположении, что будет <code>items</code>name\_\_, которого может не быть, если в sql включено предложение where.</p><p><strong> remedy </strong></p><p>поскольку для этого используется одна таблица, использование <code>tables(0)</code> позволит избежать орфографических ошибок. изучение <code>rows.count</code> также может помочь:</p><pre class="lang-vb prettyprint-override"><code>if ds.tables(0).rows.count > 0 then txtid.text = ds.tables(0).rows(0).item(1) txtid.name = ds.tables(0).rows(0).item(2) end if </code></pre><p><code>fill</code>- это функция, возвращающая число затронутых <code>rows</code>name\_\_, которые также можно протестировать:</p><pre class="lang-vb prettyprint-override"><code>if da.fill(ds, "employees") > 0 then... </code></pre><p><strong> пример 3 </strong></p><pre class="lang-vb prettyprint-override"><code>dim da as new 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 as new dataset da.fill(ds) if ds.tables("ticket\_reservation").rows.count > 0 then </code></pre><p><code>dataadapter</code>предоставит <code>tablenames</code>name\_\_, как показано в предыдущем примере, но не анализирует имена из таблицы sql или базы данных. в результате <code>ds.tables("ticket\_reservation")</code> ссылается на несуществующую таблицу.</p><p>средство <strong> </strong> такое же, ссылка на таблицу по индексу:</p><pre class="lang-vb prettyprint-override"><code>if ds.tables(0).rows.count > 0 then </code></pre><p>смотрите также <a href="http://msdn.microsoft.com/en-us/library/system.data.datatable(v=vs.110).aspx">datatable class</a> .</p><hr><h2>пути к объектам/вложенные</h2><pre class="lang-vb prettyprint-override"><code>if myfoo.bar.items isnot nothing then ... </code></pre><p>код тестирует только <code>items</code>name\_\_, в то время как <code>myfoo</code>и <code>bar</code>также могут быть nothing. средство <strong> </strong> - проверять всю цепочку или путь объектов по одному:</p><pre class="lang-vb prettyprint-override"><code>if (myfoo isnot nothing) andalso (myfoo.bar isnot nothing) andalso (myfoo.bar.items isnot nothing) then .... </code></pre><p><code>andalso</code>важно. последующие тесты не будут выполнены, если будет найдено первое условие <code>false</code>name\_\_. это позволяет коду безопасно "углубляться" в объект (ы) по одному "уровню" за раз, оценивая <code>myfoo.bar</code> только после того, как (и если) <code>myfoo</code>будет признано допустимым. цепочки объектов или пути могут быть довольно длинными при кодировании сложных объектов:</p><pre class="lang-vb prettyprint-override"><code>mybase.mynodes(3).layer.sublayer.foo.files.add("somefilename") </code></pre><p>невозможно сослаться на что-либо "вниз по течению" объекта <code>null</code>name\_\_. это также относится к элементам управления:</p><pre class="lang-vb prettyprint-override"><code>mywebbrowser.document.getelementbyid("formfld1").innertext = "some value" </code></pre><p>здесь <code>mywebbrowser</code>или <code>document</code>могут быть nothing или элемент <code>formfld1</code> может не существовать.</p><hr><h2>ui controls</h2><pre class="lang-vb prettyprint-override"><code>dim cmd5 as new 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) </code></pre><p>помимо прочего, этот код не предполагает, что пользователь, возможно, не выбрал что-то в одном или нескольких элементах управления пользовательского интерфейса. <code>listbox1.selecteditem</code> вполне может быть <code>nothing</code>name\_\_, поэтому <code>listbox1.selecteditem.tostring</code> приведет к nre.</p><p><strong> remedy </strong></p><p>проверьте данные перед их использованием (также используйте <code>option strict</code> и параметры sql):</p><pre class="lang-vb prettyprint-override"><code>dim expiry as datetime ' for text date validation if (combobox5.selecteditems.count > 0) andalso (listbox1.selecteditems.count > 0) andalso (combobox2.selecteditems.count > 0) andalso (datetime.tryparse(expiry.text, expiry) then '... do stuff else messagebox.show(...error message...) end if </code></pre><p>кроме того, вы можете использовать <code>(combobox5.selecteditem isnot nothing) andalso...</code></p><hr><h2>visual basic forms</h2><pre class="lang-vb prettyprint-override"><code>public class 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 as new list(of textbox) from {textbox1, textbox2, textbox3 ...} ' immediate nre: private somevar as string = me.controls("textbox1").text </code></pre><p>это довольно распространенный способ получить nre. в c #, в зависимости от того, как это закодировано, ide сообщит, что <code>controls</code>не существует в текущем контексте или "не может ссылаться на нестатический член". так что, в некоторой степени, это ситуация только для vb. это также сложно, потому что это может привести к каскаду сбоев.</p><p><em> массивы и коллекции не могут быть инициализированы таким образом. </em> этот код инициализации будет запущен <em> до того, как </em> конструктор создаст <code>form</code>или <code>controls</code>name\_\_. в следствии:</p><ul> <li>списки и коллекция будут просто пустыми</li> <li>массив будет содержать пять элементов nothing</li> <li>назначение <code>somevar</code>приведет к немедленному nre, потому что nothing не имеет свойства <code>.text</code></li> </ul><p>ссылка на элементы массива позже приведет к nre. если вы сделаете это в <code>form\_load</code> из-за странной ошибки, ide <em> может не </em> сообщать об исключительной ситуации, когда это происходит. исключение появится <em> позже </em>, когда ваш код попытается использовать массив. это "тихое исключение" <a href="https://stackoverflow.com/a/4934010/1070452">подробно в этом посте</a> . для наших целей ключевым моментом является то, что когда происходит что-то катастрофическое при создании формы (событие <code>sub new</code> или <code>form load</code>), исключения могут не отображаться, код выходит из процедуры и просто отображает форму.</p><p>поскольку никакой другой код в вашем событии <code>sub new</code> или <code>form load</code> не будет выполняться после nre, <em> очень многие другие вещи </em> можно оставить неинициализированными.</p><pre class="lang-vb prettyprint-override"><code>sub form\_load(...\_ '... dim name as string = nameboxes(2).text ' nre ' ... ' more code (which will likely not be executed) ' ... end sub </code></pre><p><strong> примечание </strong> это относится ко всем без исключения ссылкам на элементы управления и компонентов, что делает их недопустимыми в тех случаях, когда они:</p><pre class="lang-vb prettyprint-override"><code>public class form1 private myfiles() as string = me.openfiledialog1.filename & ... private dbcon as string = openfiledialog1.filename & ";jet oledb..." private studentname as string = textbox13.text </code></pre><p><strong> частичное средство </strong></p><p>любопытно, что vb не выдает предупреждение, но средство состоит в том, чтобы <strong> объявить </strong> контейнеры на уровне формы, но <strong> инициализировать </strong> их в обработчике событий загрузки формы, когда существуют элементы управления <strong> </strong>. это можно сделать в <code>sub new</code>, если ваш код находится после вызова <code>initializecomponent</code>name\_\_:</p><pre class="lang-vb prettyprint-override"><code>' module level declaration private nameboxes as textbox() private studentname as string ' 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 </code></pre><p>код массива еще может быть не в лесу. любые элементы управления, которые находятся в элементе управления контейнера (например, <code>groupbox</code>или <code>panel</code>name\_\_), не будут найдены в <code>me.controls</code>; они будут в коллекции controls этой panel или groupbox. также не будет возвращен элемент управления, если имя элемента управления написано с ошибкой (<code>"testbox2"</code>). в таких случаях <code>nothing</code>снова будет храниться в этих элементах массива, и при попытке обратиться к нему будет получено nre.</p><p>теперь их легко найти, когда вы знаете, что ищете: <img src="https://i.stack.imgur.com/5ndsa.jpg" alt="vs shows you the error of your ways"></p><p>"button2" находится на <code>panel</code>name\_\_</p><p><strong> remedy </strong></p><p>вместо косвенных ссылок по имени, используя форму <code>controls</code>name\_\_, используйте контрольную ссылку:</p><pre class="lang-vb prettyprint-override"><code>' declaration private 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...}) </code></pre><hr><h2>функция ничего не возвращает</h2><pre class="lang-vb prettyprint-override"><code>private bars as new list(of bars) ' declared and created public function barlist() as list(of bars) bars.clear if somecondition then for n as integer = 0 to somevalue bars.add(getbar(n)) next n else exit function end if return bars end function </code></pre><p>это тот случай, когда ide предупредит вас, что "<em> не все пути возвращают значение и может привести к (<code>nullreferenceexception</code>name\_\_) </em>". вы можете отключить предупреждение, заменив <code>exit function</code> на <code>return nothing</code>, но это не решит проблему. все, что пытается использовать возврат, когда <code>somecondition = false</code> приведет к nre:</p><pre class="lang-vb prettyprint-override"><code>blist = myfoo.barlist() for each b as bar in blist ' exception ... </code></pre><p><strong> remedy </strong></p><p>замените <code>exit function</code> в функции на <code>return blist</code>. возврат <em> пустого </em> <code>list</code>- это не то же самое, что возврат <code>nothing</code>name\_\_. если есть вероятность, что возвращаемый объект может быть <code>nothing</code>name\_\_, протестируйте его перед использованием:</p><pre class="lang-vb prettyprint-override"><code> blist = myfoo.barlist() if blist isnot nothing then... </code></pre><hr><h2>плохо реализовано try/catch</h2><p>плохо реализованный try/catch может скрыть, где проблема, и привести к новым:</p><pre class="lang-vb prettyprint-override"><code>dim dr as sqldatareader try dim lnk as linkbutton = trycast(sender, linkbutton) dim gr as gridviewrow = directcast(lnk.namingcontainer, gridviewrow) dim eid as string = 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() end if command = new sqlcommand(sqlqry, connection) 'more code fooing and barring dr = command.executereader() if dr.read() then lblfirstname.text = convert.tostring(dr("firstname")) ... end if mpe.show() catch finally command.dispose() dr.close() ' <-- nre connection.close() end try </code></pre><p>это случай, когда объект создается не так, как ожидалось, но также демонстрирует полезность счетчика пустого <code>catch</code>name\_\_.</p><p>в sql есть дополнительная запятая (после 'mailaddress'), что приводит к исключению в <code>.executereader</code>. после того, как <code>catch</code>ничего не делает, <code>finally</code>пытается выполнить очистку, но, поскольку вы не можете <code>close</code>нулевой объект <code>datareader</code>name\_\_, получается совершенно новое <code>nullreferenceexception</code>name\_\_.</p><p>пустой блок <code>catch</code>- игровая площадка дьявола. этот оп был озадачен, почему он получил nre в блоке <code>finally</code>name\_\_. в других ситуациях пустое <code>catch</code>может привести к чему-то гораздо более дальнейшему, идущему вниз по течению, и заставить вас тратить время на поиск неправильных вещей в неподходящем месте для решения проблемы. (описанное выше "тихое исключение" обеспечивает ту же развлекательную ценность.)</p><p><strong> remedy </strong></p><p>не используйте пустые блоки try/catch - позвольте коду аварийно завершить работу, чтобы вы могли a) определить причину b) определить местоположение и c) применить надлежащее решение. блоки try/catch не предназначены для сокрытия исключений от лица, обладающего уникальной квалификацией для их устранения - разработчика.</p><hr><h2>dbnull не то же самое, что nothing</h2><pre class="lang-vb prettyprint-override"><code>for each row as datagridviewrow in dgvplanning.rows if not isdbnull(row.cells(0).value) then ... </code></pre><p>функция <code>isdbnull</code>используется для проверки, равняется ли <em> значение </em> <code>system.dbnull</code>: <a href="https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/tckcces5(v=vs.90)">из msdn:</a> </p><blockquote> <p>значение system.dbnull указывает, что объект представляет отсутствующие или несуществующие данные. dbnull отличается от nothing, что указывает на то, что переменная еще не инициализирована.</p> </blockquote><p><strong> remedy </strong></p><pre class="lang-vb prettyprint-override"><code>if row.cells(0) isnot nothing then ... </code></pre><p>как и раньше, вы можете проверить на ничто, а затем для конкретного значения:</p><pre class="lang-vb prettyprint-override"><code>if (row.cells(0) isnot nothing) andalso (isdbnull(row.cells(0).value) = false) then </code></pre><p><strong> пример 2 </strong></p><pre class="lang-vb prettyprint-override"><code>dim getfoo = (from f in dbcontext.foobars where f.something = something select f).firstordefault if not isdbnull(getfoo) then if isdbnull(getfoo.user\_id) then txtfirst.text = getfoo.first\_name else ... </code></pre><p><code>firstordefault</code>возвращает первый элемент или значение по умолчанию, которое <code>nothing</code>для ссылочных типов и никогда не <code>dbnull</code>name\_\_:</p><pre class="lang-vb prettyprint-override"><code>if getfoo isnot nothing then... </code></pre><hr><h2>управления</h2><pre class="lang-vb prettyprint-override"><code>dim chk as checkbox chk = ctype(me.controls(chkname), checkbox) if chk.checked then return chk end if </code></pre><p>если <code>checkbox</code>с <code>chkname</code>не может быть найден (или существует в <code>groupbox</code>name\_\_), тогда <code>chk</code>будет nothing и попытка сослаться на какое-либо свойство приведет к исключению.</p><p><strong> remedy </strong></p><pre class="lang-vb prettyprint-override"><code>if (chk isnot nothing) andalso (chk.checked) then ... </code></pre><h3>datagridview</h3><p>у dgv есть несколько причуд, периодически замечаемых:</p><pre class="lang-vb prettyprint-override"><code>dgvbooks.datasource = loan.books dgvbooks.columns("isbn").visible = true ' nullreferenceexception dgvbooks.columns("title").defaultcellstyle.format = "c" dgvbooks.columns("author").defaultcellstyle.format = "c" dgvbooks.columns("price").defaultcellstyle.format = "c" </code></pre><p>если <code>dgvbooks</code>имеет <code>autogeneratecolumns = true</code>, он создает столбцы, но не называет их, поэтому приведенный выше код завершается ошибкой, когда он ссылается на них по имени.</p><p><strong> remedy </strong></p><p>назовите столбцы вручную или используйте указатель по индексу:</p><pre class="lang-vb prettyprint-override"><code>dgvbooks.columns(0).visible = true </code></pre><h3>пример 2 - остерегайтесь newrow</h3><pre class="lang-vb prettyprint-override"><code>xlworksheet = xlworkbook.sheets("sheet1") for i = 0 to mydgv.rowcount - 1 for j = 0 to mydgv.columncount - 1 for k as integer = 1 to mydgv.columns.count xlworksheet.cells(1, k) = mydgv.columns(k - 1).headertext xlworksheet.cells(i + 2, j + 1) = mydgv(j, i).value.tostring() next next next </code></pre><p>когда ваше <code>datagridview</code>имеет <code>allowusertoaddrows</code>как <code>true</code>(по умолчанию), <code>cells</code>в пустой/новой строке внизу будет содержать <code>nothing</code>name\_\_. большинство попыток использовать содержимое (например, <code>tostring</code>name\_\_) приведет к nre.</p><p><strong> remedy </strong></p><p>используйте цикл <code>for/each</code> и протестируйте свойство <code>isnewrow</code>name\_\_, чтобы определить, является ли он последней строкой. это работает независимо от того, является ли <code>allowusertoaddrows</code>верным или нет:</p><pre class="lang-vb prettyprint-override"><code>for each r as datagridviewrow in mydgv.rows if r.isnewrow = false then ' ok to use this row </code></pre><p>если вы используете цикл <code>for n</code>, измените число строк или используйте <code>exit for</code>, если <code>isnewrow</code>имеет значение true.</p><hr><h2>my.settings (stringcollection)</h2><p>при определенных обстоятельствах попытка использовать элемент из <code>my.settings</code>, который является <code>stringcollection</code>name\_\_, может привести к nullreference при первом его использовании. решение то же самое, но не так очевидно. рассматривать:</p><pre class="lang-vb prettyprint-override"><code>my.settings.foobars.add("ziggy") ' foobars is a string collection </code></pre><p>поскольку vb управляет настройками для вас, разумно ожидать, что он инициализирует коллекцию. это произойдет, но только если вы ранее добавили первоначальную запись в коллекцию (в редакторе настроек). поскольку коллекция (по-видимому) инициализируется при добавлении элемента, она остается <code>nothing</code>name\_\_, когда в редакторе настроек нет элементов для добавления.</p><p><strong> remedy </strong></p><p>инициализируйте коллекцию настроек в обработчике события <code>load</code>формы, если/когда это необходимо:</p><pre class="lang-vb prettyprint-override"><code>if my.settings.foobars is nothing then my.settings.foobars = new system.collections.specialized.stringcollection end if </code></pre><p>как правило, коллекция <code>settings</code>необходимо инициализировать только при первом запуске приложения. альтернативное решение - добавить начальное значение к вашей коллекции в <strong> project -> settings | foobars </strong>, сохраните проект, затем удалите поддельное значение.</p><hr><h1>ключевые моменты</h1><p>вы, вероятно, забыли оператор <code>new</code>name\_\_.</p><p>или же</p><p>то, что вы предполагали, будет работать безупречно, чтобы вернуть инициализированный объект в ваш код, не так.</p><p>не игнорируйте предупреждения компилятора (всегда) и используйте <code>option strict on</code> (всегда).</p><hr><p> <a href="https://msdn.microsoft.com/en-us/library/system.nullreferenceexception(v=vs.110).aspx">исключение msdn nullreference</a> </p>

<p>другой сценарий - когда вы преобразуете нулевой объект в <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value-types">тип значения</a> . например, код ниже:</p><pre><code>object o = null; datetime d = (datetime)o; </code></pre><p>это бросит <code>nullreferenceexception</code> на актерский состав. это кажется вполне очевидным в приведенном выше примере, но это может произойти в более сложных запоздалых сценариях, когда нулевой объект был возвращен из некоторого кода, который вам не принадлежит, и приведение, например, генерируется некоторой автоматической системой.</p><p>одним из примеров этого является этот простой фрагмент привязки asp.net с элементом управления calendar:</p><pre><code><asp:calendar runat="server" selecteddate="<%#bind("something")%>" /> </code></pre><p>здесь <code>selecteddate</code> на самом деле является свойством - типа <code>datetime</code> - типа веб-элемента управления <code>calendar</code>, и привязка может полностью вернуть что-то значение null. неявный asp.net generator создаст кусок кода, который будет эквивалентен приведенному выше коду. и это вызовет <code>nullreferenceexception</code>, который довольно трудно обнаружить, потому что он лежит в сгенерированном asp.net коде, который прекрасно компилируется ...</p>

<p>это означает, что рассматриваемая переменная ни на что не указана. я мог бы сгенерировать это так:</p><pre><code>sqlconnection connection = null; connection.open(); </code></pre><p>это приведет к ошибке, потому что, хотя я объявил переменную "<code>connection</code>", она ни на что не указана. когда я пытаюсь вызвать члена "<code>open</code>", нет ссылки для его разрешения, и он выдаст ошибку.</p><p>чтобы избежать этой ошибки:</p><ol> <li>всегда инициализируйте ваши объекты, прежде чем пытаться что-либо с ними делать.</li> <li>если вы не уверены, является ли объект пустым, проверьте его с помощью <code>object == null</code>.</li> </ol><p>инструмент jetbrains resharper будет идентифицировать каждое место в вашем коде, в котором может быть ошибка нулевой ссылки, что позволяет вам поставить нулевую проверку. эта ошибка - источник ошибок номер один, имхо.</p>

<p>это означает, что ваш код использовал переменную ссылки на объект, для которой было установлено значение null (то есть он не ссылался на фактический экземпляр объекта).</p><p>чтобы предотвратить ошибку, объекты, которые могут иметь значение null, должны быть проверены на null перед использованием.</p><pre><code>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 } </code></pre>

<p>имейте в виду, что независимо от сценария, причина всегда одинакова в .net:</p><blockquote> <p>вы пытаетесь использовать ссылочную переменную со значением <code>nothing</code>/<code>null</code>. если для ссылочной переменной задано значение <code>nothing</code>/<code>null</code>, это означает, что в действительности оно не содержит ссылку на экземпляр какого-либо объекта, который существует в куче.</p> <p>вы либо никогда не присваивали что-либо переменной, никогда не создавали экземпляр значения, назначенного переменной, либо устанавливали переменную равной <code>nothing</code>/<code>null</code> вручную, либо вызывали функцию, которая задала для переменной <code>nothing</code>/<code>null</code>.</p> </blockquote>

<p>пример этого исключения: когда вы пытаетесь что-то проверить, это пустое значение.</p><p>например:</p><pre><code>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 } </code></pre><p>среда выполнения .net генерирует исключение nullreferenceexception, когда вы пытаетесь выполнить действие с чем-то, что не было создано, то есть с кодом выше.</p><p>по сравнению с argumentnullexception, который обычно генерируется как защитная мера, если метод ожидает, что то, что ему передается, не равно нулю.</p><p>дополнительная информация находится в <em> <a href="https://www.dotnetperls.com/nullreferenceexception">c # nullreferenceexception и null parameter</a> </em>.</p>

<p>если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, оно выдаст исключение <strong> nullreferenceexception </strong>.</p><p>пример:</p><pre><code>person p = null; p.name = "harry"; // nullreferenceexception occurs here. </code></pre><p>вы можете просто избежать этого, проверив, не является ли переменная нулевой:</p><pre><code>person p = null; if (p!=null) { p.name = "harry"; // not going to run to this point } </code></pre><p>чтобы полностью понять, почему выбрасывается исключение nullreferenceexception, важно знать разницу между <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value-types">типы значений</a> и <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types">ссылочные типы</a> .</p><p>так что, если вы имеете дело с <strong> типами значений </strong>, nullreferenceexceptions может <strong> не </strong> происходят. хотя вам нужно быть начеку, когда имеете дело с <strong> ссылочными типами </strong></p><p>только ссылочные типы, как следует из названия, могут содержать ссылки или указывать буквально на ничто (или "ноль"). в то время как типы значений всегда содержат значение.</p><p><strong> типы ссылок (эти должны быть проверены): </strong></p><ul> <li>динамический</li> <li>объект</li> <li>строка</li> </ul><p><strong> типы значений (вы можете просто игнорировать эти): </strong></p><ul> <li>числовые типы</li> <li>интегральные типы</li> <li>типы с плавающей точкой</li> <li>десятичный</li> <li>bool</li> <li>пользовательские структуры</li> </ul>

<p>еще один случай, когда может произойти <code>nullreferenceexceptions</code>, - это (неправильное) использование оператора <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as"><code>as</code></a> :</p><pre><code>class book { public string name { get; set; } } class car { } car mycar = new car(); book mybook = mycar as book; // incompatible conversion --> mybook = null console.writeline(mybook.name); // nullreferenceexception </code></pre><p>здесь <code>book</code> и <code>car</code> являются несовместимыми типами; <code>car</code> не может быть преобразовано/приведено к <code>book</code>. когда это приведение не выполняется, <code>as</code> возвращает <code>null</code>. использование <code>mybook</code> после этого вызывает <code>nullreferenceexception</code>.</p><p>в общем, вы должны использовать приведение или <code>as</code>, как показано ниже:</p><p>если вы ожидаете, что преобразование типов будет всегда успешным (т.е. вы знаете, какой объект должен быть раньше времени), тогда вам следует использовать приведение:</p><pre><code>comicbook cb = (comicbook)specificbook; </code></pre><p>если вы не уверены в типе, но хотите <em> попробовать </em> использовать его в качестве определенного типа, используйте <code>as</code>:</p><pre><code>comicbook cb = specificbook as comicbook; if (cb != null) { // ... } </code></pre>

<p>вы используете объект, который содержит ссылку на нулевое значение. так что это дает нулевое исключение. в этом примере строковое значение равно нулю, и при проверке его длины произошло исключение.</p><p>пример:</p><pre><code>string value = null; if (value.length == 0) // <-- causes exception { console.writeline(value); // <-- never reached } </code></pre><p>ошибка исключения:</p><blockquote> <p>необработанное исключение:</p> <p>system.nullreferenceexception: ссылка на объект не установлена на экземпляр объекта. в program.main ()</p> </blockquote>

<p>хотя <em> то, что </em> вызывает <a href="https://msdn.microsoft.com/en-us/library/system.nullreferenceexception(v=vs.110).aspx">nullreferenceexceptions</a> и приближается к <em>, избегает/исправляет </em> такое исключение было рассмотрено в других ответах, но многие программисты еще не узнали, как самостоятельно <em> отлаживать </em> такие исключения во время разработки.</p><p>в visual studio это обычно легко благодаря <a href="https://msdn.microsoft.com/en-us/library/sc65sadd.aspx">visual studio debugger</a> .</p><hr><p>во-первых, убедитесь, что будет обнаружена правильная ошибка - см. <a href="https://stackoverflow.com/questions/4475464/">как разрешить разрыв на "system.nullreferenceexception" в vs2010?</a> <em> примечание<sup>1</sup></em></p><p>затем либо <a href="https://blogs.msdn.microsoft.com/zainnab/2010/11/01/start-debugging-vs-start-without-debugging/"><em> начните с отладки (f5) </em></a> или <a href="https://msdn.microsoft.com/en-us/library/3s68z0b3.aspx"><em> присоедините vs debugger] для запуска процесса </em></a> . иногда может быть полезно использовать <a href="https://msdn.microsoft.com/en-us/library/system.diagnostics.debugger.break(v=vs.110).aspx"><code>debugger.break</code></a> , который предложит запустить отладчик.</p><p>теперь, когда nullreferenceexception генерируется (или не обрабатывается), отладчик останавливается (помните, как установлено выше?) на строке, в которой произошло исключение. иногда ошибку легко заметить.</p><p>например, в следующей строке единственным кодом, который <em> может </em> вызвать исключение, является <code>mystring</code>, равное нулю. это можно проверить, посмотрев на <a href="http://msdn.microsoft.com/en-us/library/aa290869(v=vs.71).aspx">watch window</a> или запустив выражения в <a href="https://msdn.microsoft.com/en-us/library/f177hahy.aspx">immediate window</a> .</p><pre><code>var x = mystring.trim(); </code></pre><p>в более сложных случаях, таких как следующие, вам потребуется использовать один из методов, описанных выше (watch или immediate windows), чтобы проверить выражения, чтобы определить, был ли <code>str1</code> нулевым или <code>str2</code> нулевым.</p><pre><code>var x = str1.trim() + str2.trim(); </code></pre><p>как только <em> где </em> было обнаружено исключение throw, обычно тривиально рассуждать в обратном направлении, чтобы выяснить, где нулевое значение было [неправильно] введено -</p><p>потратьте время, необходимое для понимания причины исключения. осмотрите для нулевых выражений. проверьте предыдущие выражения, которые могли привести к таким нулевым выражениям. добавьте <a href="https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/ktf38f66(v=vs.90)">точки останова</a> и, при необходимости, выполните программу. <em> используйте отладчик. </em></p><hr><p><sup>1</sup> если break on throws слишком агрессивен и отладчик останавливается на npe в .net или сторонней библиотеке, <a href="https://msdn.microsoft.com/en-us/library/038tzxdw.aspx">break on user-unhandled</a> можно использовать для ограничения перехвата исключений. кроме того, vs2012 представляет <a href="https://msdn.microsoft.com/en-us/library/dn457346.aspx">just my code</a> , который я также рекомендую включить.</p><blockquote> <p>если вы выполняете отладку с включенным just my code, поведение будет немного другим. при включенном just my code отладчик игнорирует исключительные ситуации общеязыковой среды выполнения (clr), которые выдаются за пределы my code и не проходят через my code</p> </blockquote>

<p> <a href="https://stackoverflow.com/a/11244949/5407188">саймон мурье привел этот пример</a> :</p><pre><code>object o = null; datetime d = (datetime)o; // nullreferenceexception </code></pre><p>где <strong> <em> распаковка </em> </strong> преобразование (приведение) <em> из </em> <code>object</code> (или из одного из классов <code>system.valuetype</code> или <code>system.enum</code>, или из типа интерфейса) <em> в </em> тип значения (кроме <code>nullable<></code>) сам по себе дает <code>nullreferenceexception</code>.</p><p>в другом направлении <strong> <em> бокс </em> </strong> преобразование <em> из </em> <code>nullable<></code>, который имеет <code>hasvalue</code>, равный <code>false</code> <em> для </em> ссылочного типа, может дать ссылку <code>null</code>, которая впоследствии может привести к <code>nullreferenceexception</code>. классический пример:</p><pre><code>datetime? d = null; var s = d.tostring(); // ok, no exception (no boxing), returns "" var t = d.gettype(); // bang! d is boxed, nullreferenceexception </code></pre><p>иногда бокс бывает по-другому. например, с помощью этого неуниверсального метода расширения:</p><pre><code>public static void myextension(this object x) { x.tostring(); } </code></pre><p>следующий код будет проблематичным:</p><pre><code>datetime? d = null; d.myextension(); // leads to boxing, nullreferenceexception occurs inside the body of the called method, not here. </code></pre><p>эти случаи возникают из-за специальных правил, которые среда выполнения использует при упаковке <code>nullable<></code> экземпляров.</p>

<p>добавление случая, когда имя класса для сущности, используемой в платформе сущностей, совпадает с именем класса для файла кода веб-формы.</p><p>предположим, у вас есть веб-форма contact.aspx, класс codebehind которой - "контакт", и у вас есть имя сущности "контакт".</p><p>затем следующий код вызовет исключение nullreferenceexception при вызове context.savechanges ()</p><pre><code>contact contact = new contact { name = "abhinav"}; var context = new datacontext(); context.contacts.add(contact); context.savechanges(); // nullreferenceexception at this line </code></pre><p>ради полноты класса datacontext</p><pre><code>public class datacontext : dbcontext { public dbset<contact> contacts {get; set;} } </code></pre><p>и связаться с объектом класса. иногда классы сущностей являются частичными классами, так что вы можете расширять их и в других файлах.</p><pre><code>public partial class contact { public string name {get; set;} } </code></pre><p>ошибка возникает, когда сущность и класс codebehind находятся в одном пространстве имен. чтобы это исправить, переименуйте класс сущности или класс codebehind для contact.aspx.</p><p><strong> причина </strong> я все еще не уверен в причине. но всякий раз, когда какой-либо из классов сущностей расширяет system.web.ui.page, эта ошибка возникает.</p><p>для обсуждения взгляните на <a href="https://stackoverflow.com/questions/17136455/nullreferenceexception-in-dbcontext-savechanges">nullreferenceexception в dbcontext.savechanges ()</a> </p>

<p>другой общий случай, когда можно получить это исключение, связан с классами насмешек во время модульного тестирования. независимо от используемой среды моделирования, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом смоделированы. в частности, все свойства <code>httpcontext</code>, на которые ссылается тестируемый код, должны быть проверены.</p><p>см. " <a href="https://stackoverflow.com/questions/19314340/nullreferenceexception-thrown-when-testing-custom-authorizationattribute">nullreferenceexception, выброшенное при тестировании пользовательского authorizationattribute</a> " для несколько подробного примера.</p>

<p>у меня другая точка зрения, чтобы ответить на это. такого рода ответы <strong>"что еще я могу сделать, чтобы избежать этого?</strong>"</p><p>при работе <strong>на разных уровнях</strong>, например, в приложении mvc, контроллеру нужны сервисы для вызова бизнес-операций. в таких сценариях <strong>dependency injection container</strong> может использоваться для инициализации служб, чтобы избежать <strong>nullreferenceexception</strong>. таким образом, это означает, что вам не нужно беспокоиться о проверке на null и просто вызывать сервисы из контроллера, как если бы они всегда были доступны (и инициализированы) в виде одиночного или прототипа.</p><pre><code>public class mycontroller { private servicea servicea; private serviceb serviceb; public mycontroller(servicea servicea, serviceb serviceb) { this.servicea = servicea; this.serviceb = serviceb; } public void mymethod() { // 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(); } } </code></pre>

<p>на вопрос <strong> "что мне с этим делать" </strong> может быть много ответов.</p><p>более "формальным" способом предотвращения таких состояний ошибки <em> при разработке </em> является применение <em> <a href="http://en.wikipedia.org/wiki/design\_by\_contract">проектирование по контракту</a> </em> в ваш код. это означает, что вам нужно установить классовые <em> инварианты </em> и/или даже функции/метода <em> предварительные условия </em> и <em> постусловия </em> в вашей системе во время разработки.</p><p>короче говоря, <em> инварианты класса </em> гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушаться при обычном использовании (и, следовательно, класс не будет <em> </em> попасть в противоречивое состояние). <em> предварительные условия </em> означают, что данные, переданные в качестве входных данных для функции/метода, должны соответствовать некоторым установленным ограничениям и <strong> никогда </strong> не нарушать их, и <em> постусловия </em> означают, что вывод функции/метода должен снова следовать установленным ограничениям, не нарушая их. условия контракта не должны <strong> никогда </strong> нарушаться при выполнении безошибочной программы, поэтому проектирование по контракту проверяется на практике в режиме отладки, хотя <em> отключен в выпусках </em>, чтобы максимизировать производительность разработанной системы.</p><p>таким образом, вы можете избежать случаев <code>nullreferenceexception</code>, которые являются результатом нарушения установленных ограничений. например, если вы используете свойство объекта <code>x</code> в классе, а затем попытаетесь вызвать один из его методов, а <code>x</code> имеет нулевое значение, то это приведет к <code>nullreferenceexception</code>:</p><pre><code>public x { get; set; } public void invokex() { x.dosomething(); // if x value is null, you will get a nullreferenceexception } </code></pre><p>но если вы установите "свойство x никогда не должно иметь нулевое значение" в качестве предварительного условия метода, то вы можете предотвратить описанный выше сценарий:</p><pre><code>//using code contracts: [contractinvariantmethod] protected void objectinvariant () { contract.invariant ( x != null ); //... } </code></pre><p>по этой причине для приложений .net существует проект <em> <a href="http://msdn.microsoft.com/en-us/library/dd264808%28v=vs.110%29.aspx">code contracts</a> </em>.</p><p>в качестве альтернативы, дизайн по контракту может быть применен с помощью <em> <a href="http://en.wikipedia.org/wiki/assertion\_%28software\_development%29">утверждения</a> </em>.</p><p><strong> обновление: </strong> стоит отметить, что этот термин был придуман бертраном мейером <a href="https://www.eiffel.com/values/design-by-contract/">в связи с его разработкой языка программирования eiffel</a> .</p>

<p><code>nullreferenceexception</code> генерируется, когда мы пытаемся получить доступ к свойствам пустого объекта или когда строковое значение становится пустым, и мы пытаемся получить доступ к строковым методам.</p><p>например:</p><ol> <li> <p>при обращении к строковому методу пустой строки:</p> <pre><code>string str = string.empty; str.tolower(); // throw null reference exception </code></pre></li> <li> <p>при обращении к свойству нулевого объекта:</p> <pre><code>public class person { public string name { get; set; } } person objperson; objperson.name /// throw null refernce exception </code></pre></li> </ol>

<p><strong>tl; dr:</strong> попробуйте использовать <code>html.partial</code> вместо <code>renderpage</code></p><hr><p>я получал <code>object reference not set to an instance of an object</code>, когда пытался отобразить представление в представлении, отправив ему модель, например так:</p><pre><code>@{ myentity m = new myentity(); } @renderpage("\_myotherview.cshtml", m); // error in \_myotherview, the model was null </code></pre><p>отладка показала, что модель была нулевой внутри myotherview. пока я не изменил это на:</p><pre><code>@{ myentity m = new myentity(); } @html.partial("\_myotherview.cshtml", m); </code></pre><p>и это сработало.</p><p>более того, причина, по которой у меня не было <code>html.partial</code> для начала, заключалась в том, что visual studio <strong>иногда</strong> выбрасывает выглядящие из-за ошибки волнистые строки в <code>html.partial</code>, если он находится внутри цикла <code>foreach</code>, сконструированного по-другому, даже если на самом деле это не ошибка:</p><pre><code>@inherits system.web.mvc.webviewpage @{ viewbag.title = "entity index"; list<myentity> myentities = new list<myentity>(); myentities.add(new myentity()); myentities.add(new myentity()); myentities.add(new myentity()); } <div> @{ foreach(var m in myentities) { // 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> </code></pre><p>но я смог запустить приложение без проблем с этой "ошибкой". мне удалось избавиться от ошибки, изменив структуру цикла <code>foreach</code> так:</p><pre><code>@foreach(var m in myentities){ ... } </code></pre><p>хотя у меня такое чувство, что visual studio неправильно истолковывает амперсанды и скобки.</p>

<p><strong> что вы можете с этим поделать? </strong></p><p>здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. но есть очень мало о том, как предотвратить проблему или, по крайней мере, облегчить ее обнаружение.</p><p><strong> проверить аргументы </strong></p><p>например, методы могут проверять различные аргументы, чтобы определить, являются ли они пустыми, и генерировать <code>argumentnullexception</code>, исключение, явно созданное для этой конкретной цели.</p><p>конструктор для <code>argumentnullexception</code> даже принимает в качестве аргументов имя параметра и сообщение, чтобы вы могли точно сказать разработчику, в чем заключается проблема.</p><pre><code>public void dosomething(myobject obj) { if(obj == null) { throw new argumentnullexception("obj", "need a reference to obj."); } } </code></pre><p><strong> используйте инструменты </strong></p><p>есть также несколько библиотек, которые могут помочь. например, "resharper" может выдавать вам предупреждения во время написания кода, особенно если вы используете их атрибут: <a href="https://www.jetbrains.com/resharper/help/reference\_\_code\_annotation\_attributes.html#notnullattribute">notnullattribute</a> </p><p>есть "microsoft code contracts", где вы используете синтаксис, такой как <code>contract.requires(obj != null)</code>, который дает вам время выполнения и проверку компиляции: <a href="http://www.codeproject.com/articles/103779/introducing-code-contracts">введение в code contracts</a> .</p><p>также есть "postsharp", который позволит вам просто использовать такие атрибуты:</p><pre><code>public void dosometing([notnull] obj) </code></pre><p>сделав это и сделав postsharp частью вашего процесса сборки, <code>obj</code> будет проверяться на null во время выполнения. смотрите: <a href="http://www.postsharp.net/blog/post/validating-parameters-field-and-properties-in-postsharp-3">проверка нулевого значения postsharp</a> </p><p><strong> решение с простым кодом </strong></p><p>или вы всегда можете написать свой собственный подход, используя простой старый код. например, вот структура, которую вы можете использовать для перехвата нулевых ссылок. он смоделирован по той же концепции, что и <code>nullable<t></code>:</p><pre><code>[system.diagnostics.debuggernonusercode] public struct notnull<t> where t: class { private t \_value; public t value { get { if (\_value == null) { throw new exception("null value not allowed"); } return \_value; } set { if (value == null) { throw new exception("null value not allowed."); } \_value = value; } } public static implicit operator t(notnull<t> notnullvalue) { return notnullvalue.value; } public static implicit operator notnull<t>(t value) { return new notnull<t> { value = value }; } } </code></pre><p>вы будете использовать очень похоже на то же самое, что вы использовали бы <code>nullable<t></code>, за исключением того, что нужно выполнить с точностью до наоборот - не допустить <code>null</code>. вот некоторые примеры:</p><pre><code>notnull<person> person = null; // throws exception notnull<person> person = new person(); // ok notnull<person> person = getperson(); // throws exception if getperson() returns null </code></pre><p><code>notnull<t></code> неявно приводится к <code>t</code> и от него, поэтому вы можете использовать его практически везде, где вам это нужно. например, вы можете передать объект <code>person</code> методу, который принимает код <code>notnull<person></code>:</p><pre><code>person person = new person { name = "john" }; writename(person); public static void writename(notnull<person> person) { console.writeline(person.value.name); } </code></pre><p>как вы можете видеть выше, как и для nullable, вы получите доступ к базовому значению через свойство <code>value</code>. в качестве альтернативы, вы можете использовать явное или неявное приведение, вы можете увидеть пример с возвращаемым значением ниже:</p><pre><code>person person = getperson(); public static notnull<person> getperson() { return new person { name = "john" }; } </code></pre><p>или вы даже можете использовать его, когда метод просто возвращает <code>t</code> (в данном случае <code>person</code>), выполняя приведение. например, следующий код будет похож на приведенный выше код:</p><pre><code>person person = (notnull<person>)getperson(); public static person getperson() { return new person { name = "john" }; } </code></pre><p><strong> объединить с расширением </strong></p><p>объедините <code>notnull<t></code> с методом расширения, и вы сможете охватить еще больше ситуаций. вот пример того, как может выглядеть метод расширения:</p><pre><code>[system.diagnostics.debuggernonusercode] public static class notnullextension { public static t notnull<t>(this t @this) where t: class { if (@this == null) { throw new exception("null value not allowed"); } return @this; } } </code></pre><p>и вот пример того, как это можно использовать:</p><pre><code>var person = getperson().notnull(); </code></pre><p>github</p><p>для справки, я сделал приведенный выше код доступным на github, вы можете найти его по адресу:</p><p> <a href="https://github.com/luisperezphd/notnull">https://github.com/luisperezphd/notnull</a> </p><p><strong> функция родственного языка </strong></p><p>в c # 6.0 введен "нулевой оператор", который немного помогает в этом. с помощью этой функции вы можете ссылаться на вложенные объекты, и если любой из них является <code>null</code>, все выражение возвращает <code>null</code>.</p><p>это уменьшает количество нулевых проверок, которые вы должны сделать в некоторых случаях. синтаксис ставит знак вопроса перед каждой точкой. возьмите следующий код для примера:</p><pre><code>var address = country?.state?.county?.city; </code></pre><p>представьте, что <code>country</code> - это объект типа <code>country</code>, у которого есть свойство с именем <code>state</code> и так далее. если <code>country</code>, <code>state</code>, <code>county</code> или <code>city</code> равно <code>null</code>, тогда <code>address will be</code>null<code>. therefore you only have to check whether</code>address<code>is</code>null`.</p><p>это отличная функция, но она дает вам меньше информации. это не делает очевидным, какой из 4 является нулевым.</p><p><strong> встроенный как nullable? </strong></p><p>c # имеет сокращенное обозначение nice для <code>nullable<t></code>, вы можете сделать что-нибудь обнуляемое, поставив знак вопроса после такого типа, как <code>int?</code>.</p><p>было бы хорошо, если бы c # имел что-то вроде структуры <code>notnull<t></code> выше и имел бы подобную стенограмму, может быть, восклицательный знак (!), чтобы вы могли написать что-то вроде: <code>public void writename(person! person)</code>.</p>

<p>вы можете исправить nullreferenceexception чистым способом с помощью null-условных операторов в c # 6 и написать меньше кода для обработки нулевых проверок.</p><p>он используется для проверки на нулевое значение перед выполнением операции доступа к члену (?.) или индекса (? [).</p><p>пример</p><pre><code> var name = p?.spouse?.firstname; </code></pre><p>эквивалентно:</p><pre><code> if (p != null) { if (p.spouse != null) { name = p.spouse.firstname; } } </code></pre><p>в результате имя будет нулевым, если p равно нулю или когда p.spouse равно нулю.</p><p>в противном случае имени переменной будет присвоено значение p.spouse.firstname.</p><p>для более подробной информации: <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators">нулевые условные операторы</a> </p>

<p>строка ошибки "ссылка на объект не установлена для экземпляра объекта." гласит, что вы не назначили объект экземпляра для ссылки на объект, и все же вы получаете доступ к свойствам/методам этого объекта.</p><p>например: допустим, у вас есть класс с именем myclass, и он содержит одно свойство prop1.</p><pre><code>public class myclass { public int prop1 {get;set;} } </code></pre><p>теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:</p><pre><code>public class demo { public void testmethod() { myclass ref = null; ref.prop1 = 1; //this line throws error } } </code></pre><p>вышеприведенная строка выдает ошибку, поскольку ссылка на класс myclass объявлена, но не создана, или экземпляр объекта не назначен для ссылки на этот класс.</p><p>чтобы это исправить, вы должны создать экземпляр (назначить объект для ссылки на этот класс).</p><pre><code>public class demo { public void testmethod() { myclass ref = null; ref = new myclass(); ref.prop1 = 1; } } </code></pre>

<p>интересно, что ни один из ответов на этой странице не упоминает два случая edge, надеюсь, никто не возражает, если я добавлю их:</p><h2>пограничный вариант № 1: одновременный доступ к словарю</h2><p>общие словари в .net не являются поточно-ориентированными, и они <em>иногда</em> могут выдавать <code>nullreference</code> или даже (чаще) <code>keynotfoundexception</code> при попытке доступа к ключу из двух параллельных потоков. исключение весьма обманчиво в этом случае.</p><h2>крайний случай № 2: небезопасный код</h2><p>если <code>nullreferenceexception</code> генерируется кодом <code>unsafe</code>, вы можете просмотреть переменные-указатели и проверить их на наличие <code>intptr.zero</code> или чего-то еще. это то же самое ("исключение нулевого указателя"), но в небезопасном коде переменные часто приводятся к типам значений/массивам и т.д., и вы бьетесь головой о стену, задаваясь вопросом, как тип значения может бросить это исключение.</p><p>(кстати, еще одна причина не использовать небезопасный код, если он вам не нужен)</p>

<p>nullreferenceexception или ссылка на объект, не установленная для экземпляра объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. например:</p><p>предположим, что у вас есть класс с именем student.</p><pre><code>public class student { private string firstname; private string lastname; public string getfullname() { return firstname + lastname; } } </code></pre><p>теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.</p><pre><code>public class studentinfo { public string getstudentname() { student s; string fullname = s.getfullname(); return fullname; } } </code></pre><p>как видно из приведенного выше кода, оператор <strong>student s</strong> - объявляет только переменную типа student, обратите внимание, что на этом этапе класс student не создается. следовательно, когда выполняется оператор <strong>s.getfullname ()</strong>, он генерирует исключение nullreferenceexception.</p>

<p>ну, простыми словами:</p><p>вы пытаетесь получить доступ к объекту, который не создан или в данный момент отсутствует в памяти.</p><p>итак, как справиться с этим:</p><ol> <li> <p>отладка и пусть отладчик прервется ... он приведет вас непосредственно к сломанной переменной ... теперь ваша задача просто исправить это .. используя ключевое слово <strong> new </strong> в подходящее место.</p> </li> <li> <p>если это вызвано некоторыми <strong> командами базы данных </strong> из-за того, что объект отсутствует, то все, что вам нужно сделать, это сделать проверку на нуль и обработать ее:</p> <pre><code>if (i == null) { // handle this } </code></pre></li> <li> <p>сложнее всего .. если <strong> <a href="http://en.wikipedia.org/wiki/garbage\_collection\_%28computer\_science%29">gc</a> </strong> уже собрал объект ... обычно это происходит, если вы пытаетесь найти объект, используя строки. то есть, найдя его по имени объекта, может случиться так, что сборщик мусора уже очистил его ... это трудно найти и это станет большой проблемой ... лучший способ справиться с этим - сделать ноль проверяет, где это необходимо в процессе разработки. это сэкономит вам много времени.</p> </li> </ol><p>под поиском по имени я подразумеваю, что некоторые фреймворки позволяют вам findobjects использовать строки, и код может выглядеть следующим образом: <strong> findobject ("objectname"); </strong></p>

<p>буквально самый простой способ исправить nullreferenceexeption имеет два способа. если у вас есть gameobject, например, с прикрепленным скриптом и переменной с именем rb (hardbody), эта переменная будет начинаться с нуля, когда вы начнете свою игру.<br> вот почему вы получаете nullreferenceexeption, потому что на компьютере нет данных, хранящихся в этой переменной.</p><p>я буду использовать переменную rigidbody в качестве примера.<br> мы можем действительно легко добавлять данные несколькими способами:</p><ol> <li>добавьте rigidbody к вашему объекту с помощью addcomponent> физика> rigidbody<br> затем зайдите в свой скрипт и введите <code>rb = getcomponent<rigidbody>();</code><br> эта строка кода лучше всего работает под вашими функциями <code>start()</code> или <code>awake()</code>.</li> <li>вы можете добавить компонент программно и назначить переменную одновременно одной строкой кода: <code>rb = addcomponent<rigidbody>();</code></li> </ol><p>дополнительные примечания: если вы хотите, чтобы unity добавила компонент к вашему объекту, и вы, возможно, забыли добавить его, вы можете ввести <code>[requirecomponent(typeof(rigidbody))]</code> над объявлением класса (пробел под всеми вашими использованиями).<br> наслаждайтесь игрой и получайте удовольствие!</p>

<p>если мы рассмотрим типичные сценарии, в которых это исключение может быть выброшено, доступ к свойствам осуществляется с помощью объекта сверху.</p><p>пример:</p><pre><code>string postalcode=customer.address.postalcode; //if customer or address is null , this will through exeption </code></pre><p>здесь, если адрес равен нулю, вы получите nullreferenceexception.</p><p>таким образом, в качестве практики мы всегда должны использовать проверку null, прежде чем обращаться к свойствам в таких объектах (особенно в общем)</p><pre><code>string postalcode=customer?.address?.postalcode; //if customer or address is null , this will return null, without through a exception </code></pre>