什么是NullReferenceException,如何解决?
我有一些代码,当它执行时,它抛出一个NullReferenceException
,说:
你调用的对象是空的。
这是什么意思,我该怎么办才能解决这个错误?
原因是什么?
底线
你正在尝试使用null
(或VB.NET中Nothing
)的东西。 这意味着你要么将它设置为null
,要么你从来没有把它设置为任何东西。
像其他任何东西一样, null
被传递。 如果在方法“A”中为null
,则可能是该方法“B”将null
传递给方法“A”。
本文的其余部分将更详细地介绍许多程序员经常犯的错误,这可能会导致NullReferenceException
。
进一步来说
抛出一个NullReferenceException
的运行时总是意味着同样的事情:你正在尝试使用一个引用,并且引用没有被初始化(或者它被初始化了,但不再被初始化)。
这意味着引用为null
,并且不能通过null
引用访问成员(如方法)。 最简单的情况:
string foo = null; foo.ToUpper();
这将在第二行中抛出一个NullReferenceException
,因为您不能在指向null
的string
引用上调用实例方法ToUpper()
。
debugging
你如何find一个NullReferenceException
的来源? 除了查看exception本身,这些exception本身将会发生在它发生的位置,Visual Studio中debugging的一般规则也适用:放置战略断点并检查variables ,方法是将鼠标hover在其名称上,打开(快速)观察窗口或使用各种debugging面板,如本地和汽车。
如果您想查找引用的位置或未设置,请右键单击其名称并select“查找所有引用”。 然后,您可以在每个find的位置放置一个断点,并使用附加的debugging器运行程序。 每当debugging器断开这样一个断点,就需要确定是否期望引用是非空值,检查variables并validation它是否指向实例。
通过以这种方式遵循程序stream程,您可以find实例不应该为null的位置,以及为什么它没有正确设置。
例子
可能引发exception的一些常见情况:
通用
ref1.ref2.ref3.member
如果ref1或ref2或ref3为空,那么您将得到一个NullReferenceException
。 如果你想解决这个问题,那么通过将expression式重写为更简单的等价forms来找出哪一个是空的:
var r1 = ref1; var r2 = r1.ref2; var r3 = r2.ref3; r3.member
特别是,在HttpContext.Current.User.Identity.Name
, HttpContext.Current
可能为null,或者User
属性可能为null,或者Identity
属性可能为null。
类实例
创build引用(类)types的variables时,默认情况下设置为null
。
public class Book { public string Title { get; set; } } public class Example { public void Foo() { Book b1; string title = b1.Title; // You never initialized the b1 variable. // there is no book to get the title from. } }
类typesvariables必须被初始化或设置为已经存在的类实例。 初始化是通过使用new
关键字来完成的。
Book b1 = new Book();
间接
public class Person { public int Age { get; set; } } public class Book { public Person Author { get; set; } } public class Example { public void Foo() { Book b1 = new Book(); int authorAge = b1.Author.Age; // You never initialized the Author property. // there is no Person to get an Age from. } }
如果你想避免child(Person)空引用,你可以在父(Book)对象的构造函数中初始化它。
这同样适用于嵌套对象初始值设定项:
Book b1 = new Book { Author = { Age = 45 } };
当使用new
关键字时,它只创buildBook
的新实例,而不创buildPerson
的新实例,所以Author
的属性仍然为null
。
排列
int[] numbers = null; int n = numbers[0]; // numbers is null. There is no array to index.
数组元素
Person[] people = new Person[5]; people[0].Age = 20 // people[0] is null. The array was allocated but not // initialized. There is no Person to set the Age for.
锯齿的数组
long[][] array = new long[1][]; array[0][0] = 3; // is null because only the first dimension is yet initialized. // Use array[0] = new long[2]; first.
集合/列表/字典
Dictionary<string, int> agesForNames = null; int age = agesForNames["Bob"]; // agesForNames is null. // There is no Dictionary to perform the lookup.
范围variables(间接/延迟)
public class Person { public string Name { get; set; } } var people = new List<Person>(); people.Add(null); var names = from p in people select p.Name; string firstName = names.First(); // Exception is thrown here, but actually occurs // on the line above. "p" is null because the // first element we added to the list is null.
活动
public class Demo { public event EventHandler StateChanged; protected virtual void OnStateChanged(EventArgs e) { StateChanged(this, e); // Exception is thrown here // if no event handlers have been attached // to StateChanged event } }
错误的命名约定:
如果您将字段命名为与当地人不同,则可能意识到您从未初始化该字段。
public class Form1 { private Customer customer; private void Form1_Load(object sender, EventArgs e) { Customer customer = new Customer(); customer.Name = "John"; } private void Button_Click(object sender, EventArgs e) { MessageBox.Show(customer.Name); } }
这可以通过遵循约定来使用下划线前缀字段来解决:
private Customer _customer;
ASP.NET页面生命周期:
public partial class Issues_Edit : System.Web.UI.Page { protected TestIssue myIssue; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // Only called on first load, not when button clicked myIssue = new TestIssue(); } } protected void SaveButton_Click(object sender, EventArgs e) { myIssue.Entry = "NullReferenceException here!"; } }
ASP.NET会话值
// if the "FirstName" session value has not yet been set, // then this line will throw a NullReferenceException string firstName = Session["FirstName"].ToString();
ASP.NET MVC空视图模型
如果在ASP.NET MVC视图中引用@Model
的属性时发生exception,则需要了解在return
视图时, Model
会在操作方法中设置。 从控制器返回一个空模型(或模型属性)时,当视图访问它时会发生exception:
// Controller public class Restaurant:Controller { public ActionResult Search() { return View(); // Forgot the provide a Model here. } } // Razor view @foreach (var restaurantSearch in Model.RestaurantSearch) // Throws. { } <p>@Model.somePropertyName</p> <!-- Also throws -->
WPF控件创build顺序和事件
WPF控件是在调用InitializeComponent
中按照它们出现在可视化树中的顺序创build的。 在使用事件处理程序等早期创build的控件的情况下会引发一个NullReferenceException
,该事件处理程序等等,在InitializeComponent
中引用了晚期创build的控件。
例如 :
<Grid> <!-- Combobox declared first --> <ComboBox Name="comboBox1" Margin="10" SelectedIndex="0" SelectionChanged="comboBox1_SelectionChanged"> <ComboBoxItem Content="Item 1" /> <ComboBoxItem Content="Item 2" /> <ComboBoxItem Content="Item 3" /> </ComboBox> <!-- Label declared later --> <Label Name="label1" Content="Label" Margin="10" /> </Grid>
这里comboBox1
是在label1
之前创build的。 如果comboBox1_SelectionChanged
试图引用label1,它还不会被创build。
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e) { label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!! }
更改XAML中声明的顺序(即,在comboBox1
之前列出label1
,忽略devise原理的问题,至less可以解决NullReferenceException
。
用as
投射
var myThing = someObject as Thing;
这不会抛出InvalidCastException,但在转换失败时(以及someObject本身为null)时返回null。 所以要注意这一点。
LINQ FirstOrDefault()和SingleOrDefault()
当没有任何东西的时候,普通版本First()
和Single()
抛出exception。 在这种情况下,“OrDefault”版本返回null。 所以要注意这一点。
的foreach
当您尝试迭代空收集时foreach
抛出。 通常由返回集合的方法导致意外的null
结果。
List<int> list = null; foreach(var v in list) { } // exception
更现实的例子 – 从XML文档中select节点。 如果没有find节点,将抛出,但初始debugging显示所有属性都是有效的:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
避免的方法
显式检查null
并忽略空值。
如果您希望引用有时为空,则可以在访问实例成员之前检查它是否为null
:
void PrintName(Person p) { if (p != null) { Console.WriteLine(p.Name); } }
显式检查null
并提供一个默认值。
方法调用你期望返回一个实例可以返回null
,例如当找不到的对象时。 在这种情况下,您可以select返回默认值:
string GetCategory(Book b) { if (b == null) return "Unknown"; return b.Category; }
显式检查方法调用中的null
并抛出一个自定义exception。
你也可以抛出一个自定义的exception,只在调用代码中捕获它:
string GetCategory(string bookTitle) { var book = library.FindBook(bookTitle); // This may return null if (book == null) throw new BookNotFoundException(bookTitle); // Your custom exception return book.Category; }
如果某个值永远不能为null
,请使用Debug.Assert
,以便在发生exception时尽早发现问题。
当你在开发过程中知道一个方法可能可以,但从不应该返回null
,可以使用Debug.Assert()
在发生时尽快中断:
string GetTitle(int knownBookID) { // You know this should never return null. var book = library.GetBook(knownBookID); // Exception will occur on the next line instead of at the end of this method. Debug.Assert(book != null, "Library didn't return a book for known book ID."); // Some other code return book.Title; // Will never throw NullReferenceException in Debug mode. }
虽然这个检查不会在你的发布版本中结束 ,但是当它在发布模式下运行时, book == null
时候会导致它再次抛出NullReferenceException
。
使用GetValueOrDefault()
作为可为空的值types时提供默认值,当它们为null
。
DateTime? appointment = null; Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now)); // Will display the default value provided (DateTime.Now), because appointment is null. appointment = new DateTime(2022, 10, 20); Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now)); // Will display the appointment date, not the default
使用空合并运算符: ??
[C#]或If()
[VB]。
遇到null
时提供默认值的简写:
IService CreateService(ILogger log, Int32? frobPowerLevel) { var serviceImpl = new MyService(log ?? NullLog.Instance); // Note that the above "GetValueOrDefault()" can also be rewritten to use // the coalesce operator: serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5; }
使用null条件运算符: ?.
(在C#6和VB.NET 14中可用):
这有时也被称为安全导航或埃尔维斯(在它的形状之后)操作员。 如果运算符左侧的expression式为空,则右侧将不计算,而返回null。 这意味着这样的情况:
var title = person.Title.ToUpper();
如果这个人没有一个标题,这将会抛出一个exception,因为它试图在一个空值的属性上调用ToUpper
。
在C#5及以下版本中,可以用以下方式来保护:
var title = person.Title == null ? null : person.Title.ToUpper();
现在titlevariables将是null而不是引发exception。 C#6为此引入了更短的语法:
var title = person.Title?.ToUpper();
这将导致titlevariables为null
,如果person.Title
为null
则不会调用ToUpper
。
当然,您仍然需要检查null的title
,或者使用空条件运算符和空合并运算符( ??
)来提供默认值:
// regular null check int titleLength = 0; if (title != null) titleLength = title.Length; // If title is null, this would throw NullReferenceException // combining the `?` and the `??` operator int titleLength = title?.Length ?? 0;
NullReferenceexception – Visual Basic
Visual Basic的NullReference Exception
与C#中的NullReference Exception
没有区别。 毕竟,它们都报告了它们都使用的.NET Framework中定义的相同exception。 Visual Basic独特的原因很less(可能只有一个)。
这个答案将使用Visual Basic的术语,语法和上下文。 使用的例子来自大量的Stack Overflow问题。 这是通过使用在post中常见的情况来最大化相关性。 还为可能需要它的人提供了一点解释。 类似于你的例子很可能在这里列出。
注意:
- 这是基于概念的:没有代码可以粘贴到您的项目中。 它旨在帮助您了解导致
NullReferenceException
(NRE)的原因,如何find它,如何解决该问题,以及如何避免它。 NRE可能会导致很多方面,所以这不太可能是你唯一的遭遇。 - 这些例子(来自Stack Overflow的post)并不总是显示出最好的方式来做一些事情。
- 通常,使用最简单的补救措施。
基本含义
消息“对象未设置为对象的实例”表示您正在尝试使用尚未初始化的对象。 这归结为其中之一:
- 你的代码声明了一个对象variables,但它没有初始化它(创build一个实例或“ 实例化 ”它)
- 你的代码假设会初始化一个对象,没有
- 其他代码可能过早地使仍在使用的对象无效
寻找原因
由于问题是一个Nothing
的对象引用,答案是检查他们找出哪一个。 然后确定它为什么没有被初始化。 将鼠标放在各种variables上,Visual Studio(VS)将显示它们的值 – 罪魁祸首将是Nothing
。
你也应该删除相关代码中的任何Try / Catch块,尤其是那些Catch块中没有任何内容的代码块。 这会导致您的代码在尝试使用Nothing
的对象时崩溃。 这是你想要的,因为它会识别问题的确切位置 ,并允许你识别造成它的对象。
Catch中的MsgBox
显示Error while...
将没有什么帮助。 这个方法也会导致堆栈溢出问题,因为你不能描述实际的exception,涉及的对象,甚至是代码行。
你也可以使用Locals Window
( Debug – > Windows – > Locals )来检查你的对象。
一旦你知道问题出在什么地方,通常很容易解决问题,而且比发布一个新问题更快。
也可以看看:
- 断点
- MSDN:如何:使用Try / Catch块来捕获exception
- MSDN:exception的最佳实践
示例和补救措施
类对象/创build实例
Dim reg As CashRegister ... TextBox1.Text = reg.Amount ' NRE
问题是Dim
不会创build一个CashRegister 对象 ; 它只声明一个名为该types的reg
的variables。 声明一个对象variables并创build一个实例是两回事。
补救
New
运算符通常可用于在声明它时创build实例:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor ' Longer, more explicit form: Dim reg As CashRegister = New CashRegister
以后只适合于创build实例:
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
这将创build一个局部variablesreg
,它只存在于该上下文(sub)中。 您将在其他地方使用的模块级别为Scope
的reg
variables将保持为Nothing
。
New
运算符的缺失是NullReference Exceptions
的第一个原因 。Visual Basic尝试使用
New
重复清除该进程:使用New
运算符创build一个新对象并调用Sub New
– 构造函数 – 您的对象可以在其中执行任何其他初始化。
要清楚, Dim
(或Private
)只声明一个variables及其Type
。 variables的范围 – 无论它是存在于整个模块/类还是程序本地的 – 由其声明的位置决定。 Private | Friend | Public
Private | Friend | Public
定义访问级别,而不是范围 。
有关更多信息,请参阅:
- 新运营商
- 在Visual Basic中的作用域
- 在Visual Basic中访问级别
- 值types和引用types
数组
数组也必须被实例化:
Private arr as String()
这个数组只是被声明的,没有被创build。 有几种方法来初始化一个数组:
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}
数据types和数组大小是从正在分配的数据中推断出来的。 类/模块级声明仍然需要As <Type>
with 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
该数组已经创build,但Foo
对象没有。
补救
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
有关更多信息,请参阅:
- 期权推断声明
- 在Visual Basic中的作用域
- 在Visual Basic中的数组
列表和集合
.NET集合(其中有许多种类 – 列表,字典等)也必须实例化或创build。
Private myList As List(Of String) .. myList.Add("ziggy") ' NullReference
你出于同样的原因得到相同的exception – myList
只声明,但没有创build实例。 补救措施是一样的:
myList = New List(Of String) ' Or create an instance when declared: Private myList As New List(Of String)
一个普遍的疏忽是使用集合的Type
:
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
只是被声明的,没有实例化。 创buildFoo
的实例也不会创build内部barList
的实例。 它可能是在构造函数中这样做的意图:
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)
类 。
数据提供者对象
使用数据库为NullReference提供了很多机会,因为可以同时使用许多对象( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
….)。 注意:你使用的数据提供者无关紧要–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
数据集对象被声明,但是一个实例从未被创build。 DataAdapter
将填充现有的DataSet
,而不是创build一个。 在这种情况下,由于ds
是局部variables, 因此IDE会警告您可能会发生这种情况:
当被声明为模块/类级别variables时,与con
似乎一样,编译器无法知道对象是否由上游过程创build。 不要忽视警告。
补救
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)
一个错字是这里的一个问题: Employees
vs Employee
。 没有创build名为“Employee”的DataTable
,因此尝试访问它的NullReferenceException
结果。 另外一个潜在的问题是假定在SQL包含一个WHERE子句的时候会有这样的Items
。
补救
由于这使用一个表,使用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
是一个函数,返回受影响的Rows
数,也可以被testing:
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
将提供如上例所示的TableNames
,但不会从SQL或数据库表中parsing名称。 因此, ds.Tables("TICKET_RESERVATION")
引用一个不存在的表。
补救措施是一样的,参考表索引:
If ds.Tables(0).Rows.Count > 0 Then
另请参阅DataTable类 。
对象path/嵌套
If myFoo.Bar.Items IsNot Nothing Then ...
代码只是testingItems
而myFoo
和Bar
也可能是没有。 补救措施是一次testing一个对象的整个链或path:
If (myFoo IsNot Nothing) AndAlso (myFoo.Bar IsNot Nothing) AndAlso (myFoo.Bar.Items IsNot Nothing) Then ....
AndAlso
也很重要。 一旦遇到第一个False
条件,后续testing将不会执行。 这允许代码一次性安全地“钻取”到一个“级别”的对象中,只有在(和if) myFoo
被确定为有效之后才评估myFoo.Bar
。 编码复杂对象时,对象链或path可能会变得很长:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
无法引用null
对象的任何“下游”。 这也适用于控制:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
在这里, myWebBrowser
或Document
可能是Nothing,或者formfld1
元素可能不存在。
UI控件
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)
除此之外,这段代码并不预期用户可能没有在一个或多个UI控件中select一些东西。 ListBox1.SelectedItem
可能是Nothing
,所以ListBox1.SelectedItem.ToString
将导致一个NRE。
补救
在使用之前validation数据(也使用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窗体
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的情况。 这也是复杂的,因为它可能导致级联失败。
数组和集合不能以这种方式初始化。 此初始化代码将在构造函数创buildForm
或Controls
之前运行。 结果是:
- 列表和集合将只是空的
- 该数组将包含Nothing的五个元素
-
somevar
赋值将导致立即NRE,因为Nothing没有.Text
属性
稍后引用数组元素将导致NRE。 如果您在Form_Load
执行此操作,由于存在奇怪的错误,IDE在发生exception时可能不会报告exception。 当你的代码尝试使用数组时,将会popup一个例外。 这个“沉默的例外” 在这篇文章中详细介绍 。 就我们的目的而言,关键在于,当创build表单( Sub New
或Form Load
事件)时发生灾难性事件时,exception可能不会被报告,代码会退出过程并只显示表单。
由于在NRE之后, Sub New
或Form Load
事件中没有其他代码会运行,所以还有很多其他的东西可能未被初始化。
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没有提供警告,但补救措施是在表单级别声明容器,但是当控件确实存在时,在表单加载事件处理程序中初始化它们。 只要您的代码在InitializeComponent
调用之后,就可以在Sub New
完成:
' 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
数组代码可能还没有走出困境。 Me.Controls
找不到在容器控件(如GroupBox
或Panel
)中的任何控件; 他们将在该Panel或GroupBox的Controls集合中。 控件名称拼写错误时( "TeStBox2"
)也不会返回控件。 在这种情况下, Nothing
将再次存储在这些数组元素中,并且当您尝试引用它时将导致NRE。
这些应该很容易find,你知道你在找什么:
“Button2”驻留在Panel
补救
而不是按名称使用窗体的Controls
集合间接引用,请使用控件引用:
' 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会警告您“ 不是所有的path都返回一个值,并且可能导致NullReferenceException
”。 您可以通过将Exit Function
replace为Return Nothing
来禁止警告,但这并不能解决问题。 当someCondition = False
时,任何试图使用返回someCondition = False
都会导致NRE:
bList = myFoo.BarList() For Each b As Bar in bList ' EXCEPTION ...
补救
使用Return bList
replaceExit Function
中的Exit Function
。 返回一个空 List
与返回Nothing
。 如果返回的对象有可能是Nothing
,请在使用之前进行testing:
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
这是一个没有按预期创build的对象的情况,但也显示了一个空的Catch
的计数器的有用性。
SQL中有一个额外的逗号(在'mailaddress'之后),导致.ExecuteReader
出现exception。 在Catch
没有做什么之后, Finally
尝试执行清理,但由于您不能Close
一个空的DataReader
对象,所以会产生一个全新的NullReferenceException
。
一个空的Catch
块是魔鬼的游乐场。 这个OP很困惑他为什么要在Finally
一块获得NRE。 在其他情况下,一个空的Catch
可能会导致更糟糕的事情发生在更远的地方,导致你花时间在错误的地方看错问题。 (上述“无声的例外”提供了相同的娱乐价值。)
补救
不要使用空的Try / Catch块 – 让代码崩溃,这样你可以a)找出原因b)确定位置c)应用适当的补救措施。 Try / Catch块不打算隐藏唯一有资格修复它们的人的exception – 开发人员。
DBNull与Nothing不一样
For Each row As DataGridViewRow In dgvPlanning.Rows If Not IsDBNull(row.Cells(0).Value) Then ...
IsDBNull
函数用于testing一个值是否等于System.DBNull
: 从MSDN:
System.DBNull值表示该对象表示丢失或不存在的数据。 DBNull与Nothing不一样,表示一个variables尚未初始化。
补救
If row.Cells(0) IsNot Nothing Then ...
和以前一样,你可以testingNothing,然后获得一个特定的值:
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
returns the first item or the default value, which is Nothing
for reference types and never DBNull
:
If getFoo IsNot Nothing Then...
控制
Dim chk As CheckBox chk = CType(Me.Controls(chkName), CheckBox) If chk.Checked Then Return chk End If
If a CheckBox
with chkName
can't be found (or exists in a GroupBox
), then chk
will be Nothing and be attempting to reference any property will result in an exception.
Remedy
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
The DataGridView
The DGV has a few quirks seen periodically:
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"
If dgvBooks
has AutoGenerateColumns = True
, it will create the columns, but it does not name them, so the above code fails when it references them by name.
Remedy
Name the columns manually, or reference by index:
dgvBooks.Columns(0).Visible = True
Example 2 — Beware of the 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
When your DataGridView
has AllowUserToAddRows
as True
(the default), the Cells
in the blank/new row at the bottom will all contain Nothing
. Most attempts to use the contents (for example, ToString
) will result in an NRE.
Remedy
Use a For/Each
loop and test the IsNewRow
property to determine if it is that last row. This works whether AllowUserToAddRows
is true or not:
For Each r As DataGridViewRow in myDGV.Rows If r.IsNewRow = False Then ' ok to use this row
If you do use a For n
loop, modify the row count or use Exit For
when IsNewRow
is true.
My.Settings (StringCollection)
Under certain circumstances, trying to use an item from My.Settings
which is a StringCollection
can result in a NullReference the first time you use it. The solution is the same, but not as obvious. 考虑:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Since VB is managing Settings for you, it is reasonable to expect it to initialize the collection. It will, but only if you have previously added an initial entry to the collection (in the Settings editor). Since the collection is (apparently) initialized when an item is added, it remains Nothing
when there are no items in the Settings editor to add.
Remedy
Initialize the settings collection in the form's Load
event handler, if/when needed:
If My.Settings.FooBars Is Nothing Then My.Settings.FooBars = New System.Collections.Specialized.StringCollection End If
Typically, the Settings
collection will only need to be initialized the first time the application runs. An alternate remedy is to add an initial value to your collection in Project -> Settings | FooBars , save the project, then remove the fake value.
关键点
You probably forgot the New
operator.
要么
Something you assumed would perform flawlessly to return an initialized object to your code, did not.
Don't ignore compiler warnings (ever) and use Option Strict On
(always).
MSDN NullReference Exception
Another scenario is when you cast a null object into a value type . For example, the code below:
object o = null; DateTime d = (DateTime)o;
It will throw a NullReferenceException
on the cast. It seems quite obvious in the above sample, but this can happen in more "late-binding" intricate scenarios where the null object has been returned from some code you don't own, and the cast is for example generated by some automatic system.
One example of this is this simple ASP.NET binding fragment with the Calendar control:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Here, SelectedDate
is in fact a property – of DateTime
type – of the Calendar
Web Control type, and the binding could perfectly return something null. The implicit ASP.NET Generator will create a piece of code that will be equivalent to the cast code above. And this will raise a NullReferenceException
that is quite difficult to spot, because it lies in ASP.NET generated code which compiles fine…
It means that the variable in question is pointed at nothing. I could generate this like so:
SqlConnection connection = null; connection.Open();
That will throw the error because while I've declared the variable " connection
", it's not pointed to anything. When I try to call the member " Open
", there's no reference for it to resolve, and it will throw the error.
To avoid this error:
- Always initialize your objects before you try to do anything with them.
- If you're not sure whether the object is null, check it with
object == null
.
JetBrains' Resharper tool will identify every place in your code that has the possibility of a null reference error, allowing you to put in a null check. This error is the number one source of bugs, IMHO.
It means your code used an object reference variable that was set to null (ie it did not reference an actual object instance).
To prevent the error, objects that could be null should be tested for null before being used.
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 }
Be aware that regardless of the scenario, the cause is always the same in .NET:
You are trying to use a reference variable whose value is
Nothing
/null
. When the value isNothing
/null
for the reference variable, that means it is not actually holding a reference to an instance of any object that exists on the heap.You either never assigned something to the variable, never created an instance of the value assigned to the variable, or you set the variable equal to
Nothing
/null
manually, or you called a function that set the variable toNothing
/null
for you.
An example of this exception being thrown is: When you are trying to check something, that is null.
例如:
string testString = null; //Because it doesn't have a value (ie it's null; "Length" cannot do what it needs to do) if (testString.Length == 0) // Throws a nullreferenceexception { //Do something }
The .NET runtime will throw a NullReferenceException when you attempt to perform an action on something which hasn't been instantiated ie the code above.
In comparison to an ArgumentNullException which is typically thrown as a defensive measure if a method expects that what is being passed to it is not null.
More information is in C# NullReferenceException and Null Parameter .
If you have not initialized a reference type, and you want to set or read one of its properties, it will throw a NullReferenceException .
例:
Person p = null; p.Name = "Harry"; // NullReferenceException occurs here.
You can simply avoid this by checking if the variable is not null:
Person p = null; if (p!=null) { p.Name = "Harry"; // Not going to run to this point }
To fully understand why a NullReferenceException is thrown, it is important to know the difference between value types and reference types .
So, if you're dealing with value types , NullReferenceExceptions can not occur. Though you need to keep alert when dealing with reference types !
Only reference types, as the name is suggesting, can hold references or point literally to nothing (or 'null'). Whereas value types always contain a value.
Reference types (these ones must be checked):
- dynamic
- object
- 串
Value types (you can simply ignore these ones):
- 数字types
- Integral types
- Floating-point types
- decimal
- 布尔
- User defined structs
Another case where NullReferenceExceptions
can happen is the (incorrect) use of the as
operator :
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
Here, Book
and Car
are incompatible types; a Car
cannot be converted/cast to a Book
. When this cast fails, as
returns null
. Using mybook
after this causes a NullReferenceException
.
In general, you should use a cast or as
, as follows:
If you are expecting the type conversion to always succeed (ie. you know what the object should be ahead of time), then you should use a cast:
ComicBook cb = (ComicBook)specificBook;
If you are unsure of the type, but you want to try to use it as a specific type, then use as
:
ComicBook cb = specificBook as ComicBook; if (cb != null) { // ... }
You are using the object that contains the null value reference. So it's giving a null exception. In the example the string value is null and when checking its length, the exception occurred.
例:
string value = null; if (value.Length == 0) // <-- Causes exception { Console.WriteLine(value); // <-- Never reached }
The exception error is:
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object. at Program.Main()
Simon Mourier gave this example :
object o = null; DateTime d = (DateTime)o; // NullReferenceException
where an unboxing conversion (cast) from object
(or from one of the classes System.ValueType
or System.Enum
, or from an interface type) to a value type (other than Nullable<>
) in itself gives the NullReferenceException
.
In the other direction, a boxing conversion from a Nullable<>
which has HasValue
equal to false
to a reference type, can give a null
reference which can then later lead to a NullReferenceException
. The classic example is:
DateTime? d = null; var s = d.ToString(); // OK, no exception (no boxing), returns "" var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Sometimes the boxing happens in another way. For example with this non-generic extension method:
public static void MyExtension(this object x) { x.ToString(); }
the following code will be problematic:
DateTime? d = null; d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
These cases arise because of the special rules the runtime uses when boxing Nullable<>
instances.
While what causes a NullReferenceExceptions and approaches to avoid/fix such an exception have been addressed in other answers, what many programmers haven't learned yet is how to independently debug such exceptions during development.
In Visual Studio this is usually easy thanks to the Visual Studio Debugger .
First, make sure that the correct error is going to be caught – see How do I allow breaking on 'System.NullReferenceException' in VS2010? Note 1
Then either Start with Debugging (F5) or Attach [the VS Debugger] to Running Process . On occasion it may be useful to use Debugger.Break
, which will prompt to launch the debugger.
Now, when the NullReferenceException is thrown (or unhandled) the debugger will stop (remember the rule set above?) on the line on which the exception occurred. Sometimes the error will be easy to spot.
For instance, in the following line the only code that can cause the exception is if myString
evaluates to null. This can be verified by looking at the Watch Window or running expressions in the Immediate Window .
var x = myString.Trim();
In more advanced cases, such as the following, you'll need to use one of the techniques above (Watch or Immediate Windows) to inspect the expressions to determine if str1
was null or if str2
was null.
var x = str1.Trim() + str2.Trim();
Once where the exception is throw has been located, it's usually trivial to reason backwards to find out where the null value was [incorrectly] introduced —
Take the time required to understand the cause of the exception. Inspect for null expressions. Inspect the previous expressions which could have resulted in such null expressions. Add breakpoints and step through the program as appropriate. Use the debugger.
1 If Break on Throws is too aggressive and the debugger stops on an NPE in the .NET or 3rd-party library, Break on User-Unhandled can be used to limit the exceptions caught. Additionally, VS2012 introduces Just My Code which I recommend enabling as well.
If you are debugging with Just My Code enabled, the behavior is slightly different. With Just My Code enabled, the debugger ignores first-chance common language runtime (CLR) exceptions that are thrown outside of My Code and do not pass through My Code
Adding a case when the class name for entity used in entity framework is same as class name for a web form code-behind file.
Suppose you have a web form Contact.aspx whose codebehind class is Contact and you have an entity name Contact.
Then following code will throw a NullReferenceException when you call context.SaveChanges()
Contact contact = new Contact { Name = "Abhinav"}; var context = new DataContext(); context.Contacts.Add(contact); context.SaveChanges(); // NullReferenceException at this line
For the sake of completeness DataContext class
public class DataContext : DbContext { public DbSet<Contact> Contacts {get; set;} }
and Contact entity class. Sometimes entity classes are partial classes so that you can extend them in other files too.
public partial class Contact { public string Name {get; set;} }
The error occurs when both the entity and codebehind class are in same namespace. To fix this, rename the entity class or the codebehind class for Contact.aspx.
Reason I am still not sure about the reason. But whenever any of the entity class will extend System.Web.UI.Page this error occurs.
For discussion have a look at NullReferenceException in DbContext.saveChanges()
Another general case where one might receive this exception involves mocking classes during unit testing. Regardless of the mocking framework being used, you must ensure that all appropriate levels of the class hierarchy are properly mocked. In particular, all properties of HttpContext
which are referenced by the code under test must be mocked.
See " NullReferenceException thrown when testing custom AuthorizationAttribute " for a somewhat verbose example.
I have a different perspective to answering this. This sort of answers "what else can I do to avoid it? "
When working across different layers , for example in an MVC application, a controller needs services to call business operations. In such scenarios Dependency Injection Container can be used to initialize the services to avoid the NullReferenceException . So that means you don't need to worry about checking for null and just call the services from the controller as though they will always to available (and initialized) as either a singleton or a prototype.
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(); } }
On the matter of "what should I do about it" , there can be many answers.
A more "formal" way of preventing such error conditions while developing is applying design by contract in your code. This means you need to set class invariants , and/or even function/method preconditions and postconditions on your system, while developing.
In short, class invariants ensure that there will be some constraints in your class that will not get violated in normal use (and therefore, the class will not get in an inconsistent state). Preconditions mean that data given as input to a function/method must follow some constraints set and never violate them, and postconditions mean that a function/method output must follow the set constraints again without ever violating them. Contract conditions should never be violated during execution of a bug-free program, therefore design by contract is checked in practice in debug mode, while being disabled in releases , to maximize the developed system performance.
This way, you can avoid NullReferenceException
cases that are results of violation of the constraints set. For example, if you use an object property X
in a class and later try to invoke one of its methods and X
has a null value, then this will lead to NullReferenceException
:
public X { get; set; } public void InvokeX() { X.DoSomething(); // if X value is null, you will get a NullReferenceException }
But if you set "property X must never have a null value" as method precondition, then you can prevent the scenario described before:
//Using code contracts: [ContractInvariantMethod] protected void ObjectInvariant () { Contract.Invariant ( X != null ); //... }
For this cause, Code Contracts project exists for .NET applications.
Alternatively, design by contract can be applied using assertions .
UPDATE: It is worth mentioning that the term was coined by Bertrand Meyer in connection with his design of the Eiffel programming language .
A NullReferenceException
is thrown when we are trying to access Properties of a null object or when a string value becomes empty and we are trying to access string methods.
例如:
-
When a string method of an empty string accessed:
string str = string.Empty; str.ToLower(); // throw null reference exception
-
When a property of a null object accessed:
Public Class Person { public string Name { get; set; } } Person objPerson; objPerson.Name /// throw Null refernce Exception
TL;DR: Try using Html.Partial
instead of Renderpage
I was getting Object reference not set to an instance of an object
when I tried to render a View within a View by sending it a Model, like this:
@{ MyEntity M = new MyEntity(); } @RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Debugging showed the model was Null inside MyOtherView. Until I changed it to:
@{ MyEntity M = new MyEntity(); } @Html.Partial("_MyOtherView.cshtml", M);
它的工作。
Furthermore, the reason I didn't have Html.Partial
to begin with was because Visual Studio sometimes throws error-looking squiggly lines under Html.Partial
if it's inside a differently constructed foreach
loop, even though it's not really an error:
@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>
But I was able to run the application with no problems with this "error". I was able to get rid of the error by changing the structure of the foreach
loop to look like this:
@foreach(var M in MyEntities){ ... }
Although I have a feeling it was because Visual Studio was misreading the ampersands and brackets.
What can you do about it?
There is a lot of good answers here explaining what a null reference is and how to debug it. But there is very little on how to prevent the issue or at least make it easier to catch.
Check arguments
For example, methods can check the different arguments to see if they are null and throw an ArgumentNullException
, an exception obviously created for this exact purpose.
The constructor for the ArgumentNullException
even takes the name of the parameter and a message as arguments so you can tell the developer exactly what the problem is.
public void DoSomething(MyObject obj) { if(obj == null) { throw new ArgumentNullException("obj", "Need a reference to obj."); } }
Use Tools
There are also several libraries that can help. "Resharper" for example can provide you with warnings while you are writing code, especially if you use their attribute: NotNullAttribute
There's "Microsoft Code Contracts" where you use syntax like Contract.Requires(obj != null)
which gives you runtime and compile checking: Introducing Code Contracts .
There's also "PostSharp" which will allow you to just use attributes like this:
public void DoSometing([NotNull] obj)
By doing that and making PostSharp part of your build process obj
will be checked for null at runtime. See: PostSharp null check
Plain Code Solution
Or you can always code your own approach using plain old code. For example here is a struct that you can use to catch null references. It's modeled after the same concept as 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 }; } }
You would use very similar to the same way you would use Nullable<T>
, except with the goal of accomplishing exactly the opposite – to not allow 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>
is implicitly cast to and from T
so you can use it just about anywhere you need it. For example, you can pass a Person
object to a method that takes a NotNull<Person>
:
Person person = new Person { Name = "John" }; WriteName(person); public static void WriteName(NotNull<Person> person) { Console.WriteLine(person.Value.Name); }
As you can see above as with nullable you would access the underlying value through the Value
property. Alternatively, you can use an explicit or implicit cast, you can see an example with the return value below:
Person person = GetPerson(); public static NotNull<Person> GetPerson() { return new Person { Name = "John" }; }
Or you can even use it when the method just returns T
(in this case Person
) by doing a cast. For example, the following code would just like the code above:
Person person = (NotNull<Person>)GetPerson(); public static Person GetPerson() { return new Person { Name = "John" }; }
Combine with Extension
Combine NotNull<T>
with an extension method and you can cover even more situations. Here is an example of what the extension method can look like:
[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; } }
And here is an example of how it could be used:
var person = GetPerson().NotNull();
GitHub上
For your reference I made the code above available on GitHub, you can find it at:
https://github.com/luisperezphd/NotNull
Related Language Feature
C# 6.0 introduced the "null-conditional operator" that helps with this a little. With this feature, you can reference nested objects and if any one of them is null
the whole expression returns null
.
This reduces the number of null checks you have to do in some cases. The syntax is to put a question mark before each dot. Take the following code for example:
var address = country?.State?.County?.City;
Imagine that country
is an object of type Country
that has a property called State
and so on. If country
, State
, County
, or City
is null
then address will be
null . Therefore you only have to check whether
address is
null`.
It's a great feature, but it gives you less information. It doesn't make it obvious which of the 4 is null.
Built-in like Nullable?
C# has a nice shorthand for Nullable<T>
, you can make something nullable by putting a question mark after the type like so int?
。
It would be nice if C# had something like the NotNull<T>
struct above and had a similar shorthand, maybe the exclamation point (!) so that you could write something like: public void WriteName(Person! person)
.
The error line "Object reference not set to an instance of an object. " states that you have not assigned instance object to a object reference and still you are accessing properies/methods of that object.
for example: let say you have a class called myClass and it contains one property prop1.
public Class myClass { public int prop1 {get;set;} }
Now you are accessing this prop1 in some other class just like below:
public class Demo { public void testMethod() { myClass ref = null; ref.prop1 = 1; //This line throws error } }
above line throws error because reference of class myClass is declared but not instantiated or an instance of object is not assigned to referecne of that class.
To fix this you have to instantiate (assign object to reference of that class).
public class Demo { public void testMethod() { myClass ref = null; ref = new myClass(); ref.prop1 = 1; } }
Interestingly, none of the answers on this page mention the two edge cases, hope no one minds if I add them:
Edge case #1: concurrent access to a Dictionary
Generic dictionaries in .NET are not thread-safe and they sometimes might throw a NullReference
or even (more frequent) a KeyNotFoundException
when you try to access a key from two concurrent threads. The exception is quite misleading in this case.
Edge case #2: unsafe code
If a NullReferenceException
is thrown by unsafe
code, you might look at your pointer variables, and check them for IntPtr.Zero
or something. Which is the same thing ("null pointer exception"), but in unsafe code, variables are often cast to value-types/arrays, etc., and you bang your head against the wall, wondering how a value-type can throw this exception.
(Another reason for non-using unsafe code unless you need it, by the way)
NullReferenceException or Object reference not set to an instance of an object occurs when an object of the class you are trying to use is not instantiated. 例如:
Assume that you have a class named Student.
public class Student { private string FirstName; private string LastName; public string GetFullName() { return FirstName + LastName; } }
Now, consider another class where you are trying to retrieve the student's full name.
public class StudentInfo { public string GetStudentName() { Student s; string fullname = s.GetFullName(); return fullname; } }
As seen in the above code, the statement Student s – only declares the variable of type Student, note that the Student class is not instantiated at this point. Hence, when the statement s.GetFullName() gets executed, it will throw the NullReferenceException.
Well, in simple terms:
You are trying to access an object that isn't created or currently not in memory.
So how to tackle this:
-
Debug and let the debugger break… It will directly take you to the variable that is broken… Now your task is to simply fix this.. Using the new keyword in the appropriate place.
-
If it is caused on some database commands because the object isn't present then all you need to do is do a null check and handle it:
if (i == null) { // Handle this }
-
The hardest one .. if the GC collected the object already… This generally occurs if you are trying to find an object using strings… That is, finding it by name of the object then it may happen that the GC might already cleaned it up… This is hard to find and will become quite a problem… A better way to tackle this is do null checks wherever necessary during the development process. 这会为你节省很多时间。
By finding by name I mean some framework allow you to FIndObjects using strings and the code might look like this: FindObject("ObjectName");
If we consider common scenarios where this exception can be thrown, accessing properties withing object at the top.
例如:
string postalcode=Customer.Address.PostalCode; //if customer or address is null , this will through exeption
in here , if address is null , then you will get NullReferenceException.
So, as a practice we should always use null check, before accessing properties in such objects (specially in generic)
string postalcode=Customer?.Address?.PostalCode; //if customer or address is null , this will return null, without through a exception
If one is getting this message during saving or compiling the build, just close all the files and then open any file to compile and save.
For me the reason was that I had rename the file and old file was still open.
It means you are trying to manipulate something which has reference but not yet initialized
The first thing to do here is check every instance created.
Use breakpoints , watches , inspect your varibale values.
Follow stack trace and search for exact row and column which is creating problem
To use methods and member of an object you first have to create that object. If you didn't create it (variable that should hold the object is not initialized), but you try to use it's methods or variables you'll get that error.
Sometime you may just forgot to do initialization.
Edited: new can't return null, but fire's exception when failed. Long time ago it was the case in some languages, but not any more. Thanks @John Saunders for pointing that out.
This is basically is a Null reference exception . As Microsoft states-
A NullReferenceException exception is thrown when you try to access a member of a type whose value is null.
这意味着什么?
That means if any member which doesn't hold any value and we are making that member to perform certain task then the system will undoubtedly toss a message and say-
“Hey wait, that member has no values so it can't perform the task which you are handing it over.”
The exception itself says that something is being referred but whose value is not being set. So this denotes that it only occurs while using reference types as Value types are non-nullable.
NullReferenceException won't occur if we are using Value type members.
class Program { static void Main(string[] args) { string str = null; Console.WriteLine(str.Length); Console.ReadLine(); } }
The above code shows simple string which is assigned with a null value.
Now, when I try to print the length of the string str , I do get An unhandled exception of type 'System.NullReferenceException' occurred message because member str is pointing to null and there can't be any length of null.
' NullReferenceException ' also occurs when we forget to instantiate a reference type.
Suppose I have a class and member method in it. I have not instantiated my class but only named my class. Now if I try to use the method, the compiler will throw an error or issue a warning (depending on the compiler).
class Program { static void Main(string[] args) { MyClass1 obj; obj.foo(); //Use of unassigned local variable 'obj' } } public class MyClass1 { internal void foo() { Console.WriteLine("hello from foo"); } }
Compiler for the above code raises an error that variable obj is unassigned which signifies that our variable has null values or nothing. Compiler for the above code raises an error that variable obj is unassigned which signifies that our variable has null values or nothing.
Why it occurs?
-
NullReferenceException arises due to our fault for not checking the object's value. We often leave the object values unchecked in the code development.
-
It also arises when we forget to instantiate our objects. Using methods, properties, collections etc. which can return or set null values can also be the cause of this exception.
How can it be avoided?
There are various ways and methods to avoid this renowned exception:
-
Explicit Checking: We should adhere to the tradition of checking the objects, properties, methods, arrays, and collections whether they are null. This can be simply implemented using conditional statements like if-else if-else etc.
-
Exception handling: One of the important ways of managing this exception. Using simple try-catch-finally blocks we can control this exception and also maintain a log of it. This can be very useful when your application is on production stage.
-
Null operators: Null Coalescing operator and null conditional operators can also be used in handy while setting values to objects, variables, properties and fields.
-
Debugger: For developers, we have the big weapon of Debugging with us. If have we face NullReferenceException during the development face we can use the debugger to get to the source of the exception.
-
In-built method: System methods such as GetValueOrDefault(),IsNullOrWhiteSpace() and IsNullorEmpty() checks for nulls and assign the default value if there is a null value.
There are many good answers already here. You can also check more detailed description with examples on my blog .
Hope this helps too!
You are trying to access an object that isn't created or currently not in memory.
When I get this error, I add the following code to any event handler that triggers the error.
if (!IsLoaded) return;
The ! means "not", FYI. So if the object in question isn't loaded, the program terminates the execution and prevents the crash.
There is a scenario that can happen that is Class related. The question ended up getting closed prior to my stating the resolution: https://stackoverflow.com/questions/43348009/unable-to-instantiate-class
Beware of classes not instantiating: If any part of your constructor in a class throws a null reference exception
the class does not instantiate. In my case it was trying to get a connection string from the web.config that that did not exist.
I instantiated a class:
ClassName myClass = new ClassName(); myClass.RunSomeMethod();
Inside the class itself was a call to get a connection string from the web.config
. This part of the constructor threw an null value exception so myClass
was null.
If you ever have a situation where a class in not instantiating, try making sure that no part of the class constructor Is throwing a null value exception
. F-11 and step through the class and make sure there are no nulls.