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

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

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


当前回答

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

请参阅“测试自定义AuthorizationAttribute时引发的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
}

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<>实例时使用的特殊规则。

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

关于“我该怎么办”的问题,可以有很多答案。

在开发时防止这种错误情况的一种更“正式”的方法是在代码中应用契约设计。这意味着在开发时,需要在系统上设置类不变量,和/或甚至函数/方法前置条件和后置条件。

简而言之,类不变量确保类中有一些约束在正常使用中不会被违反(因此,类不会处于不一致的状态)。前置条件意味着作为函数/方法输入的数据必须遵循某些约束集,并且永远不会违反这些约束,后置条件意味着函数/方法输出必须再次遵循这些约束集,而永远不会违反它们。在执行无错误程序期间,不应违反合同条件,因此,在调试模式下实际检查合同设计,而在发布版本中禁用,以最大化开发的系统性能。

通过这种方式,可以避免由于违反约束集而导致的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应用程序存在代码合同项目。

或者,可以使用断言应用契约设计。

更新:值得一提的是,这个词是Bertrand Meyer在设计Eiffel编程语言时创造的。

当我们试图访问空对象的财产时,或者当字符串值变为空并且我们试图访问字符串方法时,会抛出NullReferenceException。

例如:

访问空字符串的字符串方法时:string str=string.Empty;str.ToLower();//抛出空引用异常访问空对象的属性时:公共类人员{公共字符串名称{get;set;}}人员对象人员;objPerson.Name///抛出空引用异常