it-swarm-ru.tech

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

У меня есть некоторый код, и когда он выполняется, он выдает NullReferenceException, говоря:

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

Что это значит, и что я могу сделать, чтобы исправить эту ошибку?

1877
John Saunders

Исключение NullReference - Visual Basic

NullReference Exception для Visual Basic не отличается от кода в C # . В конце концов, они оба сообщают об одном и том же исключении, определенном в .NET Framework, которое они оба используют. Причины, уникальные для Visual Basic, встречаются редко (возможно, только одна).

В этом ответе будут использоваться термины, синтаксис и контекст Visual Basic. Используемые примеры взяты из большого количества прошлых вопросов о переполнении стека. Это делается для максимизации релевантности с помощью видов ситуаций, часто встречающихся в постах. Немного больше объяснений также предоставляется тем, кому это может понадобиться. Пример, похожий на ваш, очень , скорее всего, приведен здесь.

Примечание:

  1. Это основано на концепции: нет кода для вставки в ваш проект. Он предназначен для того, чтобы помочь вам понять, что вызывает NullReferenceException(NRE), как его найти, как исправить и как его избежать. NRE может быть вызвано многими способами, так что вряд ли это будет ваша единственная встреча.
  2. Примеры (из сообщений Stack Overflow) не всегда показывают лучший способ сделать что-либо в первую очередь.
  3. Как правило, самое простое средство используется.

Основное значение

Сообщение "Объект не установлен в экземпляр объекта" означает, что вы пытаетесь использовать объект, который не был инициализирован. Это сводится к одному из них:

  • Ваш код объявил переменную объекта, но он не инициализировал ее (создал экземпляр или ' создать экземпляр 'это)
  • То, что ваш код предполагал инициализировать объект, не
  • Возможно, другой код преждевременно лишил законной силы объект, все еще используемый

В поисках причины

Поскольку проблема заключается в ссылке на объект Nothingname__, ответ состоит в том, чтобы изучить их, чтобы выяснить, какая из них. Затем определите, почему он не инициализирован. Наведите указатель мыши на различные переменные, и Visual Studio (VS) покажет их значения - виновником будет Nothingname__.

IDE debug display

Вам также следует удалить все блоки Try/Catch из соответствующего кода, особенно те, в которых нет ничего в блоке Catch. Это приведет к сбою вашего кода при попытке использовать объект Nothingname__. Это то, что вы хотите , потому что он определит точное местоположение проблемы и позволит вам определить объект, вызывающий его.

MsgBoxв Catch, который отображает Error while..., мало поможет. Этот метод также приводит к очень плохим вопросам переполнения стека, потому что вы не можете описать фактическое исключение, задействованный объект или даже строку кода, где это происходит.

Вы также можете использовать Locals Window ( Debug -> Windows -> Locals ) для проверки ваших объектов.

После того, как вы знаете, в чем и где проблема, ее обычно довольно легко исправить и быстрее, чем опубликовать новый вопрос.

Смотрите также:

Примеры и средства правовой защиты

Объекты класса/Создание экземпляра

Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE

Проблема в том, что Dimне создает объект CashRegister ; он только объявляет переменную с именем regэтого типа. Объявление переменной объекта и создание экземпляра - это две разные вещи.

Remedy

Оператор Newчасто можно использовать для создания экземпляра при его объявлении:

Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor

' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister

Когда уместно создать экземпляр позже:

Private reg As CashRegister         ' Declare
  ...
reg = New CashRegister()            ' Create instance

Примечание: Не снова используйте Dimв процедуре, включая конструктор (Sub New):

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

Это создаст локальную переменную regname__, которая существует только в этом контексте (подпункте). Переменная regс уровнем модуля Scopename__, которую вы будете использовать везде, остается Nothingname__.

Отсутствие оператора Newявляется # 1 причиной NullReference Exceptions, замеченной в рассмотренных вопросах переполнения стека.

Visual Basic несколько раз пытается сделать процесс очистки понятным, используя NewNAME _: используя NewNAME _ Оператор создает новый объект и вызывает Sub New - конструктор - - где ваш объект может выполнить любую другую инициализацию.

Для ясности, только Dim(или Privatename__) объявляет переменную и ее Typename__. Область переменной - существует ли она для всего модуля/класса или является локальной для процедуры - определяется как где это объявлено. Private | Friend | Public определяет уровень доступа, а не Область .

Для получения дополнительной информации см .:


Массивы

Массивы также должны быть созданы:

Private arr as String()

Этот массив только объявлен, но не создан. Существует несколько способов инициализации массива:

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) {}

Примечание. Начиная с VS 2010, при инициализации локального массива с использованием литерала и Option Infer элементы As <Type> и Newявляются необязательными:

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}

Тип данных и размер массива выводятся из назначаемых данных. Для объявлений уровня класса/модуля все еще требуется As <Type> с Option Strict:

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

Пример: массив объектов класса

Dim arrFoo(5) As Foo

For i As Integer = 0 To arrFoo.Count - 1
   arrFoo(i).Bar = i * 10       ' Exception
Next

Массив создан, а объекты Fooв нем - нет.

Remedy

For i As Integer = 0 To arrFoo.Count - 1
    arrFoo(i) = New Foo()         ' Create Foo instance
    arrFoo(i).Bar = i * 10
Next

Использование функции List(Of T) весьма затруднит получение элемента без действительного объекта:

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

Для получения дополнительной информации см .:


Списки и Коллекции

Коллекции .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 As New List(Of String)

Обычный недосмотр - это класс, который использует коллекцию Typename__:

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

Любая процедура приведет к NRE, потому что barListтолько объявлен, но не создан. Создание экземпляра Fooтакже не создаст экземпляр внутреннего barListname__. Возможно, это было сделано в конструкторе:

Public Sub New         ' Constructor
    ' Stuff to do when a new Foo is created...
    barList = New List(Of Bar)
End Sub

Как и раньше, это неверно:

Public Sub New()
    ' Creates another barList local to this procedure
     Dim barList As New List(Of Bar)
End Sub

Для получения дополнительной информации см. List(Of T) Class .


Объекты провайдера данных

Работа с базами данных предоставляет множество возможностей для NullReference, поскольку одновременно может использоваться несколько объектов (Commandname__, Connectionname__, Transactionname__, Datasetname__, DataTablename__, DataRowsname __....). Примечание: Неважно, какой поставщик данных вы используете - MySQL, SQL Server, OleDB и т.д. - понятия одинаковы.

Пример 1

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

Как и раньше, объект набора данных dsбыл объявлен, но экземпляр так и не был создан. DataAdapterзаполнит существующее DataSetname__, а не создаст его. В этом случае, поскольку dsявляется локальной переменной, IDE предупреждает вас , что это может произойти:

img

Когда объявлено как переменная уровня модуля/класса, как это имеет место с conname__, компилятор не может знать, был ли объект создан процедурой выше по потоку. Не игнорируйте предупреждения.

Remedy

Dim ds As New DataSet

Пример 2

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)

Опечатка - проблема здесь: Employeesvs Employeename__. Не было создано DataTableс именем "Employee", поэтому NullReferenceExceptionпытается получить к нему доступ. Другая потенциальная проблема заключается в предположении, что будет Itemsname__, которого может не быть, если в SQL включено предложение WHERE.

Remedy

Поскольку для этого используется одна таблица, использование Tables(0) позволит избежать орфографических ошибок. Изучение Rows.Count также может помочь:

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

Fill- это функция, возвращающая число затронутых Rowsname__, которые также можно протестировать:

If da.Fill(ds, "Employees") > 0 Then...

Пример 3

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

DataAdapterпредоставит TableNamesname__, как показано в предыдущем примере, но не анализирует имена из таблицы SQL или базы данных. В результате ds.Tables("TICKET_RESERVATION") ссылается на несуществующую таблицу.

Средство такое же, ссылка на таблицу по индексу:

If ds.Tables(0).Rows.Count > 0 Then

Смотрите также DataTable Class .


Пути к объектам/вложенные

If myFoo.Bar.Items IsNot Nothing Then
   ...

Код тестирует только Itemsname__, в то время как myFooи Barтакже могут быть Nothing. Средство - проверять всю цепочку или путь объектов по одному:

If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....

AndAlsoважно. Последующие тесты не будут выполнены, если будет найдено первое условие Falsename__. Это позволяет коду безопасно "углубляться" в объект (ы) по одному "уровню" за раз, оценивая myFoo.Bar только после того, как (и если) myFooбудет признано допустимым. Цепочки объектов или пути могут быть довольно длинными при кодировании сложных объектов:

myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")

Невозможно сослаться на что-либо "вниз по течению" объекта nullname__. Это также относится к элементам управления:

myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"

Здесь myWebBrowserили Documentмогут быть Nothing или элемент formfld1 может не существовать.


UI Controls

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)

Помимо прочего, этот код не предполагает, что пользователь, возможно, не выбрал что-то в одном или нескольких элементах управления пользовательского интерфейса. ListBox1.SelectedItem вполне может быть Nothingname__, поэтому ListBox1.SelectedItem.ToString приведет к NRE.

Remedy

Проверьте данные перед их использованием (также используйте Option Strict и параметры SQL):

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

Кроме того, вы можете использовать (ComboBox5.SelectedItem IsNot Nothing) AndAlso...


Visual Basic Forms

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

Это довольно распространенный способ получить NRE. В C #, в зависимости от того, как это закодировано, IDE сообщит, что Controlsне существует в текущем контексте или "не может ссылаться на нестатический член". Так что, в некоторой степени, это ситуация только для VB. Это также сложно, потому что это может привести к каскаду сбоев.

Массивы и коллекции не могут быть инициализированы таким образом. Этот код инициализации будет запущен до того, как конструктор создаст Formили Controlsname__. В следствии:

  • Списки и Коллекция будут просто пустыми
  • Массив будет содержать пять элементов Nothing
  • Назначение somevarприведет к немедленному NRE, потому что Nothing не имеет свойства .Text

Ссылка на элементы массива позже приведет к NRE. Если вы сделаете это в Form_Load из-за странной ошибки, IDE может не сообщать об исключительной ситуации, когда это происходит. Исключение появится позже , когда ваш код попытается использовать массив. Это "тихое исключение" подробно в этом посте . Для наших целей ключевым моментом является то, что когда происходит что-то катастрофическое при создании формы (событие Sub New или Form Load), исключения могут не отображаться, код выходит из процедуры и просто отображает форму.

Поскольку никакой другой код в вашем событии Sub New или Form Load не будет выполняться после NRE, очень многие другие вещи можно оставить неинициализированными.

Sub Form_Load(..._
   '...
   Dim name As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

Примечание это относится ко всем без исключения ссылкам на элементы управления и компонентов, что делает их недопустимыми в тех случаях, когда они:

Public Class Form1

    Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
    Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
    Private studentName As String = TextBox13.Text

Частичное Средство

Любопытно, что VB не выдает предупреждение, но средство состоит в том, чтобы объявить контейнеры на уровне формы, но инициализировать их в обработчике событий загрузки формы, когда существуют элементы управления . Это можно сделать в Sub New, если ваш код находится после вызова InitializeComponentname__:

' 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

Код массива еще может быть не в лесу. Любые элементы управления, которые находятся в элементе управления контейнера (например, GroupBoxили Panelname__), не будут найдены в Me.Controls; они будут в коллекции Controls этой Panel или GroupBox. Также не будет возвращен элемент управления, если имя элемента управления написано с ошибкой ("TeStBox2"). В таких случаях Nothingснова будет храниться в этих элементах массива, и при попытке обратиться к нему будет получено NRE.

Теперь их легко найти, когда вы знаете, что ищете: VS shows you the error of your ways

"Button2" находится на Panelname__

Remedy

Вместо косвенных ссылок по имени, используя форму Controlsname__, используйте контрольную ссылку:

' 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...})

Функция ничего не возвращает

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

Это тот случай, когда IDE предупредит вас, что " не все пути возвращают значение и может привести к (NullReferenceExceptionname__) ". Вы можете отключить предупреждение, заменив Exit Function на Return Nothing, но это не решит проблему. Все, что пытается использовать возврат, когда someCondition = False приведет к NRE:

bList = myFoo.BarList()
For Each b As Bar in bList      ' EXCEPTION
      ...

Remedy

Замените Exit Function в функции на Return bList. Возврат пустого List- это не то же самое, что возврат Nothingname__. Если есть вероятность, что возвращаемый объект может быть Nothingname__, протестируйте его перед использованием:

 bList = myFoo.BarList()
 If bList IsNot Nothing Then...

Плохо реализовано Try/Catch

Плохо реализованный Try/Catch может скрыть, где проблема, и привести к новым:

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

Это случай, когда объект создается не так, как ожидалось, но также демонстрирует полезность счетчика пустого Catchname__.

В SQL есть дополнительная запятая (после 'mailaddress'), что приводит к исключению в .ExecuteReader. После того, как Catchничего не делает, Finallyпытается выполнить очистку, но, поскольку вы не можете Closeнулевой объект DataReadername__, получается совершенно новое NullReferenceExceptionname__.

Пустой блок Catch- игровая площадка дьявола. Этот ОП был озадачен, почему он получил NRE в блоке Finallyname__. В других ситуациях пустое Catchможет привести к чему-то гораздо более дальнейшему, идущему вниз по течению, и заставить вас тратить время на поиск неправильных вещей в неподходящем месте для решения проблемы. (Описанное выше "тихое исключение" обеспечивает ту же развлекательную ценность.)

Remedy

Не используйте пустые блоки Try/Catch - позвольте коду аварийно завершить работу, чтобы вы могли a) определить причину b) определить местоположение и c) применить надлежащее решение. Блоки Try/Catch не предназначены для сокрытия исключений от лица, обладающего уникальной квалификацией для их устранения - разработчика.


DBNull не то же самое, что Nothing

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...

Функция IsDBNullиспользуется для проверки, равняется ли значение System.DBNull: из MSDN:

Значение System.DBNull указывает, что объект представляет отсутствующие или несуществующие данные. DBNull отличается от Nothing, что указывает на то, что переменная еще не инициализирована.

Remedy

If row.Cells(0) IsNot Nothing Then ...

Как и раньше, вы можете проверить на Ничто, а затем для конкретного значения:

If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then

Пример 2

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
       ...

FirstOrDefaultвозвращает первый элемент или значение по умолчанию, которое Nothingдля ссылочных типов и никогда не DBNullname__:

If getFoo IsNot Nothing Then...

Управления

Dim chk As CheckBox

chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
    Return chk
End If

Если CheckBoxс chkNameне может быть найден (или существует в GroupBoxname__), тогда chkбудет Nothing и попытка сослаться на какое-либо свойство приведет к исключению.

Remedy

If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...

DataGridView

У DGV есть несколько причуд, периодически замечаемых:

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"

Если dgvBooksимеет AutoGenerateColumns = True, он создает столбцы, но не называет их, поэтому приведенный выше код завершается ошибкой, когда он ссылается на них по имени.

Remedy

Назовите столбцы вручную или используйте указатель по индексу:

dgvBooks.Columns(0).Visible = True

Пример 2 - Остерегайтесь NewRow

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

Когда ваше DataGridViewимеет AllowUserToAddRowsкак True(по умолчанию), Cellsв пустой/новой строке внизу будет содержать Nothingname__. Большинство попыток использовать содержимое (например, ToStringname__) приведет к NRE.

Remedy

Используйте цикл For/Each и протестируйте свойство IsNewRowname__, чтобы определить, является ли он последней строкой. Это работает независимо от того, является ли AllowUserToAddRowsверным или нет:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

Если вы используете цикл For n, измените число строк или используйте Exit For, если IsNewRowимеет значение true.


My.Settings (StringCollection)

При определенных обстоятельствах попытка использовать элемент из My.Settings, который является StringCollectionname__, может привести к NullReference при первом его использовании. Решение то же самое, но не так очевидно. Рассматривать:

My.Settings.FooBars.Add("ziggy")         ' foobars is a string collection

Поскольку VB управляет настройками для вас, разумно ожидать, что он инициализирует коллекцию. Это произойдет, но только если вы ранее добавили первоначальную запись в коллекцию (в редакторе настроек). Поскольку коллекция (по-видимому) инициализируется при добавлении элемента, она остается Nothingname__, когда в редакторе настроек нет элементов для добавления.

Remedy

Инициализируйте коллекцию настроек в обработчике события Loadформы, если/когда это необходимо:

If My.Settings.FooBars Is Nothing Then
    My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If

Как правило, коллекция Settingsнеобходимо инициализировать только при первом запуске приложения. Альтернативное решение - добавить начальное значение к вашей коллекции в Project -> Settings | FooBars , сохраните проект, затем удалите поддельное значение.


Ключевые моменты

Вы, вероятно, забыли оператор Newname__.

или же

То, что вы предполагали, будет работать безупречно, чтобы вернуть инициализированный объект в ваш код, не так.

Не игнорируйте предупреждения компилятора (всегда) и используйте Option Strict On (всегда).


исключение MSDN NullReference

300
Nat Pongjardenlarp

Другой сценарий - когда вы преобразуете нулевой объект в тип значения . Например, код ниже:

object o = null;
DateTime d = (DateTime)o;

Это бросит NullReferenceException на актерский состав. Это кажется вполне очевидным в приведенном выше примере, но это может произойти в более сложных запоздалых сценариях, когда нулевой объект был возвращен из некоторого кода, который вам не принадлежит, и приведение, например, генерируется некоторой автоматической системой.

Одним из примеров этого является этот простой фрагмент привязки ASP.NET с элементом управления Calendar:

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

Здесь SelectedDate на самом деле является свойством - типа DateTime - типа веб-элемента управления Calendar, и привязка может полностью вернуть что-то значение null. Неявный ASP.NET Generator создаст кусок кода, который будет эквивалентен приведенному выше коду. И это вызовет NullReferenceException, который довольно трудно обнаружить, потому что он лежит в сгенерированном ASP.NET коде, который прекрасно компилируется ...

224
Simon Mourier

Это означает, что рассматриваемая переменная ни на что не указана. Я мог бы сгенерировать это так:

SqlConnection connection = null;
connection.Open();

Это приведет к ошибке, потому что, хотя я объявил переменную "connection", она ни на что не указана. Когда я пытаюсь вызвать члена "Open", нет ссылки для его разрешения, и он выдаст ошибку.

Чтобы избежать этой ошибки:

  1. Всегда инициализируйте ваши объекты, прежде чем пытаться что-либо с ними делать.
  2. Если вы не уверены, является ли объект пустым, проверьте его с помощью object == null.

Инструмент JetBrains Resharper будет идентифицировать каждое место в вашем коде, в котором может быть ошибка нулевой ссылки, что позволяет вам поставить нулевую проверку. Эта ошибка - источник ошибок номер один, ИМХО.

156
Chris B. Behrens

Это означает, что ваш код использовал переменную ссылки на объект, для которой было установлено значение 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
}
152
Jonathan Wood

Имейте в виду, что независимо от сценария, причина всегда одинакова в .NET:

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

Вы либо никогда не присваивали что-либо переменной, никогда не создавали экземпляр значения, назначенного переменной, либо устанавливали переменную равной Nothing/null вручную, либо вызывали функцию, которая задала для переменной Nothing/null.

95
code master

Пример этого исключения: Когда вы пытаетесь что-то проверить, это пустое значение.

Например:

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 # NullReferenceException и Null Parameter.

86
Alex KeySmith

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, оно выдаст исключение 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, важно знать разницу между типы значений и ссылочные типы .

Так что, если вы имеете дело с типами значений , NullReferenceExceptions может не происходят. Хотя вам нужно быть начеку, когда имеете дело с ссылочными типами

Только ссылочные типы, как следует из названия, могут содержать ссылки или указывать буквально на ничто (или "ноль"). В то время как типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • строка

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей точкой
  • десятичный
  • bOOL
  • Пользовательские структуры
83
Fabian Bigler

Еще один случай, когда может произойти NullReferenceExceptions, - это (неправильное) использование оператора as :

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

Здесь Book и Car являются несовместимыми типами; Car не может быть преобразовано/приведено к Book. Когда это приведение не выполняется, as возвращает null. Использование mybook после этого вызывает NullReferenceException.

В общем, вы должны использовать приведение или as, как показано ниже:

Если вы ожидаете, что преобразование типов будет всегда успешным (т.е. вы знаете, какой объект должен быть раньше времени), тогда вам следует использовать приведение:

ComicBook cb = (ComicBook)specificBook;

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

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}
77
Jonathon Reinhart

Вы используете объект, который содержит ссылку на нулевое значение. Так что это дает нулевое исключение. В этом примере строковое значение равно нулю, и при проверке его длины произошло исключение.

Пример:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

Ошибка исключения:

Необработанное исключение:

System.NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта. в Program.Main ()

64
user1814380

Хотя то, что вызывает NullReferenceExceptions и приближается к , избегает/исправляет такое исключение было рассмотрено в других ответах, но многие программисты еще не узнали, как самостоятельно отлаживать такие исключения во время разработки.

В Visual Studio это обычно легко благодаря Visual Studio Debugger .


Во-первых, убедитесь, что будет обнаружена правильная ошибка - см. Как разрешить разрыв на "System.NullReferenceException" в VS2010? Примечание1

Затем либо Начните с отладки (F5) или Присоедините VS Debugger] для запуска процесса . Иногда может быть полезно использовать Debugger.Break , который предложит запустить отладчик.

Теперь, когда NullReferenceException генерируется (или не обрабатывается), отладчик останавливается (помните, как установлено выше?) На строке, в которой произошло исключение. Иногда ошибку легко заметить.

Например, в следующей строке единственным кодом, который может вызвать исключение, является myString, равное нулю. Это можно проверить, посмотрев на Watch Window или запустив выражения в Immediate Window .

var x = myString.Trim();

В более сложных случаях, таких как следующие, вам потребуется использовать один из методов, описанных выше (Watch или Immediate Windows), чтобы проверить выражения, чтобы определить, был ли str1 нулевым или str2 нулевым.

var x = str1.Trim() + str2.Trim();

Как только где было обнаружено исключение throw, обычно тривиально рассуждать в обратном направлении, чтобы выяснить, где нулевое значение было [неправильно] введено -

Потратьте время, необходимое для понимания причины исключения. Осмотрите для нулевых выражений. Проверьте предыдущие выражения, которые могли привести к таким нулевым выражениям. Добавьте точки останова и, при необходимости, выполните программу. Используйте отладчик.


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

62
user2864740

Саймон Мурье привел этот пример :

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

где распаковка преобразование (приведение) из object (или из одного из классов System.ValueType или System.Enum, или из типа интерфейса) в тип значения (кроме Nullable<>) сам по себе дает NullReferenceException.

В другом направлении бокс преобразование из 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

Иногда бокс бывает по-другому. Например, с помощью этого неуниверсального метода расширения:

public static void MyExtension(this object x)
{
  x.ToString();
}

следующий код будет проблематичным:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

Эти случаи возникают из-за специальных правил, которые среда выполнения использует при упаковке Nullable<> экземпляров.

57
Jeppe Stig Nielsen

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

Предположим, у вас есть веб-форма Contact.aspx, класс codebehind которой - "Контакт", и у вас есть имя сущности "Контакт".

Затем следующий код вызовет исключение NullReferenceException при вызове context.SaveChanges ()

Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

Ради полноты класса DataContext

public class DataContext : DbContext 
{
    public DbSet<Contact> Contacts {get; set;}
}

и Связаться с объектом класса. Иногда классы сущностей являются частичными классами, так что вы можете расширять их и в других файлах.

public partial class Contact 
{
    public string Name {get; set;}
}

Ошибка возникает, когда сущность и класс codebehind находятся в одном пространстве имен. Чтобы это исправить, переименуйте класс сущности или класс codebehind для Contact.aspx.

Причина Я все еще не уверен в причине. Но всякий раз, когда какой-либо из классов сущностей расширяет System.Web.UI.Page, эта ошибка возникает.

Для обсуждения взгляните на NullReferenceException в DbContext.saveChanges ()

41
AbhinavRanjan

Другой общий случай, когда можно получить это исключение, связан с классами насмешек во время модульного тестирования. Независимо от используемой среды моделирования, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом смоделированы. В частности, все свойства HttpContext, на которые ссылается тестируемый код, должны быть проверены.

См. " NullReferenceException, выброшенное при тестировании пользовательского AuthorizationAttribute " для несколько подробного примера.

40
John Saunders

У меня другая точка зрения, чтобы ответить на это. Такого рода ответы "Что еще я могу сделать, чтобы избежать этого?"

При работе на разных уровнях, например, в приложении MVC, контроллеру нужны сервисы для вызова бизнес-операций. В таких сценариях Dependency Injection Container может использоваться для инициализации служб, чтобы избежать NullReferenceException. Таким образом, это означает, что вам не нужно беспокоиться о проверке на null и просто вызывать сервисы из контроллера, как если бы они всегда были доступны (и инициализированы) в виде одиночного или прототипа.

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();
    }
}
39
Mukus

На вопрос "что мне с этим делать" может быть много ответов.

Более "формальным" способом предотвращения таких состояний ошибки при разработке является применение проектирование по контракту в ваш код. Это означает, что вам нужно установить классовые инварианты и/или даже функции/метода предварительные условия и постусловия в вашей системе во время разработки.

Короче говоря, инварианты класса гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушаться при обычном использовании (и, следовательно, класс не будет попасть в противоречивое состояние). Предварительные условия означают, что данные, переданные в качестве входных данных для функции/метода, должны соответствовать некоторым установленным ограничениям и никогда не нарушать их, и постусловия означают, что вывод функции/метода должен снова следовать установленным ограничениям, не нарушая их. Условия контракта не должны никогда нарушаться при выполнении безошибочной программы, поэтому проектирование по контракту проверяется на практике в режиме отладки, хотя отключен в выпусках , чтобы максимизировать производительность разработанной системы.

Таким образом, вы можете избежать случаев NullReferenceException, которые являются результатом нарушения установленных ограничений. Например, если вы используете свойство объекта X в классе, а затем попытаетесь вызвать один из его методов, а X имеет нулевое значение, то это приведет к NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

Но если вы установите "свойство X никогда не должно иметь нулевое значение" в качестве предварительного условия метода, то вы можете предотвратить описанный выше сценарий:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

По этой причине для приложений .NET существует проект Code Contracts.

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

ОБНОВЛЕНИЕ: Стоит отметить, что этот термин был придуман Бертраном Мейером в связи с его разработкой языка программирования Eiffel .

37
Nick Louloudakis

NullReferenceException генерируется, когда мы пытаемся получить доступ к свойствам пустого объекта или когда строковое значение становится пустым, и мы пытаемся получить доступ к строковым методам.

Например:

  1. При обращении к строковому методу пустой строки:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
    
  2. При обращении к свойству нулевого объекта:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 
    
35
Hemant Bavle

TL; DR: Попробуйте использовать Html.Partial вместо Renderpage


Я получал Object reference not set to an instance of an object, когда пытался отобразить представление в представлении, отправив ему модель, например так:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

Отладка показала, что модель была нулевой внутри MyOtherView. Пока я не изменил это на:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

И это сработало.

Более того, причина, по которой у меня не было Html.Partial для начала, заключалась в том, что Visual Studio иногда выбрасывает выглядящие из-за ошибки волнистые строки в Html.Partial, если он находится внутри цикла foreach, сконструированного по-другому, даже если на самом деле это не ошибка:

@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>

Но я смог запустить приложение без проблем с этой "ошибкой". Мне удалось избавиться от ошибки, изменив структуру цикла foreach так:

@foreach(var M in MyEntities){
    ...
}

Хотя у меня такое чувство, что Visual Studio неправильно истолковывает амперсанды и скобки.

30
Travis Heeter

Что вы можете с этим поделать?

Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но есть очень мало о том, как предотвратить проблему или, по крайней мере, облегчить ее обнаружение.

Проверить аргументы

Например, методы могут проверять различные аргументы, чтобы определить, являются ли они пустыми, и генерировать ArgumentNullException, исключение, явно созданное для этой конкретной цели.

Конструктор для ArgumentNullException даже принимает в качестве аргументов имя параметра и сообщение, чтобы вы могли точно сказать разработчику, в чем заключается проблема.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Используйте инструменты

Есть также несколько библиотек, которые могут помочь. Например, "Resharper" может выдавать вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute

Есть "Microsoft Code Contracts", где вы используете синтаксис, такой как Contract.Requires(obj != null), который дает вам время выполнения и проверку компиляции: Введение в Code Contracts .

Также есть "PostSharp", который позволит вам просто использовать такие атрибуты:

public void DoSometing([NotNull] obj)

Сделав это и сделав PostSharp частью вашего процесса сборки, obj будет проверяться на null во время выполнения. Смотрите: проверка нулевого значения PostSharp

Решение с простым кодом

Или вы всегда можете написать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать для перехвата нулевых ссылок. Он смоделирован по той же концепции, что и Nullable<T>:

[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 };
    }
}

Вы будете использовать очень похоже на то же самое, что вы использовали бы Nullable<T>, за исключением того, что нужно выполнить с точностью до наоборот - не допустить null. Вот некоторые примеры:

NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null

NotNull<T> неявно приводится к T и от него, поэтому вы можете использовать его практически везде, где вам это нужно. Например, вы можете передать объект Person методу, который принимает код NotNull<Person>:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull<Person> person)
{
    Console.WriteLine(person.Value.Name);
}

Как вы можете видеть выше, как и для nullable, вы получите доступ к базовому значению через свойство Value. В качестве альтернативы, вы можете использовать явное или неявное приведение, вы можете увидеть пример с возвращаемым значением ниже:

Person person = GetPerson();

public static NotNull<Person> GetPerson()
{
    return new Person { Name = "John" };
}

Или вы даже можете использовать его, когда метод просто возвращает T (в данном случае Person), выполняя приведение. Например, следующий код будет похож на приведенный выше код:

Person person = (NotNull<Person>)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Объединить с расширением

Объедините NotNull<T> с методом расширения, и вы сможете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:

[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;
    }
}

И вот пример того, как это можно использовать:

var person = GetPerson().NotNull();

GitHub

Для справки, я сделал приведенный выше код доступным на GitHub, вы можете найти его по адресу:

https://github.com/luisperezphd/NotNull

Функция родственного языка

В C # 6.0 введен "нулевой оператор", который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты, и если любой из них является null, все выражение возвращает null.

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

var address = country?.State?.County?.City;

Представьте, что country - это объект типа Country, у которого есть свойство с именем State и так далее. Если country, State, County или City равно null, тогда address will benull. Therefore you only have to check whetheraddressisnull`.

Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.

Встроенный как Nullable?

C # имеет сокращенное обозначение Nice для Nullable<T>, вы можете сделать что-нибудь обнуляемое, поставив знак вопроса после такого типа, как int?.

Было бы хорошо, если бы C # имел что-то вроде структуры NotNull<T> выше и имел бы подобную стенограмму, может быть, восклицательный знак (!), Чтобы вы могли написать что-то вроде: public void WriteName(Person! person).

22
Luis Perez

Вы можете исправить 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.

Для более подробной информации: Нулевые условные операторы

9
M.Hassan

Строка ошибки "Ссылка на объект не установлена ​​для экземпляра объекта." Гласит, что вы не назначили объект экземпляра для ссылки на объект, и все же вы получаете доступ к свойствам/методам этого объекта.

например: допустим, у вас есть класс с именем myClass, и он содержит одно свойство prop1.

public Class myClass
{
   public int prop1 {get;set;}
}

Теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

вышеприведенная строка выдает ошибку, поскольку ссылка на класс myClass объявлена, но не создана, или экземпляр объекта не назначен для ссылки на этот класс.

Чтобы это исправить, вы должны создать экземпляр (назначить объект для ссылки на этот класс).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}
8
Jaimin Dave

Интересно, что ни один из ответов на этой странице не упоминает два случая Edge, надеюсь, никто не возражает, если я добавлю их:

Пограничный вариант № 1: одновременный доступ к словарю

Общие словари в .NET не являются поточно-ориентированными, и они иногда могут выдавать NullReference или даже (чаще) KeyNotFoundException при попытке доступа к ключу из двух параллельных потоков. Исключение весьма обманчиво в этом случае.

Крайний случай № 2: небезопасный код

Если NullReferenceException генерируется кодом unsafe, вы можете просмотреть переменные-указатели и проверить их на наличие IntPtr.Zero или чего-то еще. Это то же самое ("исключение нулевого указателя"), но в небезопасном коде переменные часто приводятся к типам значений/массивам и т.д., И вы бьетесь головой о стену, задаваясь вопросом, как тип значения может бросить это исключение.

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

8
jazzcat

NullReferenceException или ссылка на объект, не установленная для экземпляра объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:

Предположим, что у вас есть класс с именем Student.

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

Как видно из приведенного выше кода, оператор Student s - объявляет только переменную типа Student, обратите внимание, что на этом этапе класс Student не создается. Следовательно, когда выполняется оператор s.GetFullName (), он генерирует исключение NullReferenceException.

3
Nick

Ну, простыми словами:

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

Итак, как справиться с этим:

  1. Отладка и пусть отладчик прервется ... Он приведет вас непосредственно к сломанной переменной ... Теперь ваша задача просто исправить это .. Используя ключевое слово new в подходящее место.

  2. Если это вызвано некоторыми командами базы данных из-за того, что объект отсутствует, то все, что вам нужно сделать, это сделать проверку на нуль и обработать ее:

    if (i == null) {
        // Handle this
    }
    
  3. Сложнее всего .. если GC уже собрал объект ... Обычно это происходит, если вы пытаетесь найти объект, используя строки. То есть, найдя его по имени объекта, может случиться так, что сборщик мусора уже очистил его ... Это трудно найти и это станет большой проблемой ... Лучший способ справиться с этим - сделать ноль проверяет, где это необходимо в процессе разработки. Это сэкономит вам много времени.

Под поиском по имени я подразумеваю, что некоторые фреймворки позволяют вам FIndObjects использовать строки, и код может выглядеть следующим образом: FindObject ("ObjectName");

2
Akash Gutha

Буквально самый простой способ исправить NullReferenceExeption имеет два способа. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (hardbody), эта переменная будет начинаться с нуля, когда вы начнете свою игру.
Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.

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

  1. Добавьте RigidBody к вашему объекту с помощью AddComponent> Физика> Rigidbody
    Затем зайдите в свой скрипт и введите rb = GetComponent<Rigidbody>();
    Эта строка кода лучше всего работает под вашими функциями Start() или Awake().
  2. Вы можете добавить компонент программно и назначить переменную одновременно одной строкой кода: rb = AddComponent<RigidBody>();

Дополнительные примечания: Если вы хотите, чтобы Unity добавила компонент к вашему объекту, и вы, возможно, забыли добавить его, вы можете ввести [RequireComponent(typeof(RigidBody))] над объявлением класса (пробел под всеми вашими использованиями).
Наслаждайтесь игрой и получайте удовольствие!

0
CausticLasagne

Если мы рассмотрим типичные сценарии, в которых это исключение может быть выброшено, доступ к свойствам осуществляется с помощью объекта сверху.

Пример:

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
0
Hiran