我有一些代码,当它执行时,它会抛出NullReferenceException,说:

对象引用未设置为对象的实例。

这意味着什么,我可以做什么来修复这个错误?


当前回答

另一个可能收到此异常的一般情况是在单元测试期间模拟类。无论使用何种模拟框架,您都必须确保正确模拟类层次结构的所有适当级别。特别是,被测试代码引用的HttpContext的所有财产都必须进行模拟。

请参阅“测试自定义AuthorizationAttribute时引发的NullReferenceException”,以获取一些详细的示例。

其他回答

Simon Mourier举了一个例子:

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

其中,从对象(或从System.ValueType或System.Enum类之一,或从接口类型)到值类型(非Nullable<>)的拆箱转换(强制转换)本身会产生NullReferenceException。

在另一个方向上,从HasValue等于false的Nullable<>到引用类型的装箱转换可能会给出一个空引用,然后会导致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<>实例时使用的特殊规则。

有趣的是,本页的答案中没有一个提到两种边缘情况:

边缘案例#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”(对象引用未设置为对象的实例)。根据这个线程,这个问题已经知道了很长一段时间,在编写时仍然没有解决。

当实体框架中使用的实体的类名与web表单代码隐藏文件的类名相同时,添加一种情况。

假设您有一个web表单Contact.aspx,其代码尾类为Contact,实体名称为Contact。

然后,当您调用context.SaveChanges()时,以下代码将引发NullReferenceException

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

和Contact实体类。有时实体类是分部类,因此您也可以在其他文件中扩展它们。

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

当实体和代码尾类都在同一命名空间中时,会发生错误。要解决此问题,请重命名Contact.aspx的实体类或codebehind类。

原因我仍然不确定原因。但每当任何实体类将扩展System.Web.UI.Page时,都会发生此错误。

有关讨论,请查看DbContext.saveChanges()中的NullReferenceException

简单来说:

您正在尝试访问未创建或当前不在内存中的对象。

那么如何解决这个问题:

调试并让调试器中断。。。它将直接将您带到被破坏的变量。。。现在你的任务是简单地解决这个问题。。在适当的位置使用新关键字。如果这是由于对象不存在而在某些数据库命令上导致的,那么您需要做的就是执行空检查并处理它:如果(i==空){//处理这个}最难的。。如果GC已经收集了对象。。。如果您试图使用字符串查找对象,通常会发生这种情况。。。也就是说,通过对象的名称查找它,那么GC可能已经清理了它。。。这很难找到,会成为一个很大的问题。。。解决这一问题的更好方法是在开发过程中,在必要时进行空检查。这将为您节省大量时间。

通过名称查找,我的意思是某些框架允许您使用字符串查找对象,代码可能如下:FindObject(“ObjectName”);

错误行“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;
     }
}