我有一些代码,当它执行时,它会抛出NullReferenceException,说:
对象引用未设置为对象的实例。
这意味着什么,我可以做什么来修复这个错误?
我有一些代码,当它执行时,它会抛出NullReferenceException,说:
对象引用未设置为对象的实例。
这意味着什么,我可以做什么来修复这个错误?
当前回答
请注意,无论情况如何,.NET中的原因总是相同的:
您正在尝试使用值为Nothing/null的引用变量。当引用变量的值为Nothing/null时,这意味着它实际上没有保存对堆上存在的任何对象实例的引用。您要么从未向变量赋值,要么从未创建分配给变量的值的实例,要么手动将变量设置为Nothing/null,要么为您调用了将变量设置成Nothing/nnull的函数。
其他回答
另一种可能发生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是不兼容的类型;汽车不能转换成书。当此强制转换失败时,as返回null。在此之后使用mybook会导致NullReferenceException。
通常,应使用强制转换或,如下所示:
如果您希望类型转换总是成功的(即,您知道对象应该是什么),那么应该使用强制转换:
ComicBook cb = (ComicBook)specificBook;
如果您不确定该类型,但希望尝试将其用作特定类型,请将其用作:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
当您尝试使用的类的对象未实例化时,会发生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。
有趣的是,本页的答案中没有一个提到两种边缘情况:
边缘案例#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”(对象引用未设置为对象的实例)。根据这个线程,这个问题已经知道了很长一段时间,在编写时仍然没有解决。
错误行“Object reference not set to an instance of a Object.”表示您尚未将实例对象分配给对象引用,但仍在访问该对象的财产/方法。
例如:假设您有一个名为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 an error
}
}
上述行引发错误,因为类myClass的引用已声明,但未实例化,或者对象的实例未分配给该类的引用。
要解决这个问题,必须实例化(将对象分配给该类的引用)。
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
我有不同的观点来回答这个问题。这种回答是“我还能做什么来避免它?”
当跨不同层工作时,例如在MVC应用程序中,控制器需要服务来调用业务操作。在这种情况下,依赖注入容器可用于初始化服务以避免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();
}
}