我有一些代码,当它执行时,它会抛出NullReferenceException,说:
对象引用未设置为对象的实例。
这意味着什么,我可以做什么来修复这个错误?
我有一些代码,当它执行时,它会抛出NullReferenceException,说:
对象引用未设置为对象的实例。
这意味着什么,我可以做什么来修复这个错误?
当前回答
当您尝试使用的类的对象未实例化时,会发生NullReferenceException或未设置对象实例的Object引用。例如:
假设您有一个名为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。
其他回答
当您尝试使用的类的对象未实例化时,会发生NullReferenceException或未设置对象实例的Object引用。例如:
假设您有一个名为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。
这意味着您的代码使用了一个设置为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
}
有趣的是,本页的答案中没有一个提到两种边缘情况:
边缘案例#1:对字典的并发访问
.NET中的泛型字典不是线程安全的,当您尝试从两个并发线程访问密钥时,它们有时可能会抛出NullReference,甚至(更频繁)抛出KeyNotFoundException。在这种情况下,这个例外情况很容易引起误解。
边缘案例#2:不安全代码
如果不安全代码引发NullReferenceException,您可以查看指针变量,并检查它们是否存在IntPtr.Zero或其他内容。这是同一回事(“空指针异常”),但在不安全的代码中,变量通常被转换为值类型/数组等,你会把头撞在墙上,想知道值类型如何抛出此异常。
(顺便说一句,除非您需要,否则不使用不安全代码的另一个原因。)
边缘案例3:Visual Studio多监视器设置,辅助监视器的DPI设置与主监视器不同
此边缘案例是特定于软件的,属于Visual Studio 2019 IDE(以及可能更早的版本)。
一种重现问题的方法:将任何组件从工具箱拖到非主监视器上的Windows窗体上,该窗体的DPI设置与主监视器不同,然后会弹出一个“Object reference not set to A instance of A Object”(对象引用未设置为对象的实例)。根据这个线程,这个问题已经知道了很长一段时间,在编写时仍然没有解决。
这意味着所讨论的变量没有指向任何对象。我可以这样生成:
SqlConnection connection = null;
connection.Open();
这将引发错误,因为虽然我声明了变量“connection”,但它没有指向任何对象。当我尝试将成员称为“Open”时,没有任何引用可供它解析,它会抛出错误。
要避免此错误,请执行以下操作:
在尝试对对象执行任何操作之前,请始终初始化对象。如果您不确定对象是否为空,请使用object==null进行检查。
JetBrains的ReSharper工具将识别代码中可能出现空引用错误的每个位置,从而允许您进行空检查。这个错误是错误的头号来源,IMHO。
更新C#8.02019:可为空的引用类型
C#8.0引入了可为null的引用类型和不可为null引用类型。因此,必须只检查可为null的引用类型,以避免出现NullReferenceException。
如果尚未初始化引用类型,并且希望设置或读取其财产之一,则会抛出NullReferenceException。
例子:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
您可以通过检查变量是否为空来避免这种情况:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
要完全理解为什么会引发NullReferenceException,必须了解值类型和[引用类型][3]之间的区别。
因此,如果要处理值类型,则不能出现NullReferenceExceptions。尽管在处理引用类型时需要保持警惕!
正如名称所暗示的那样,只有引用类型可以保存引用或直接指向任何对象(或“null”)。而值类型始终包含值。
引用类型(必须选中这些类型):
动态对象一串
值类型(您可以忽略这些类型):
数字类型整数类型浮点类型十进制的布尔用户定义的结构