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

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

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


当前回答

抛出此异常的一个示例是:当您试图检查某个对象时,该对象为空。

例如:

string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)

if (testString.Length == 0) // Throws a nullreferenceexception
{
    //Do something
} 

当您尝试对尚未实例化的对象(即上面的代码)执行操作时,.NET运行时将抛出NullReferenceException。

与ArgumentNullException相比,ArgumentNullException通常在方法期望传递给它的内容不为null时作为防御措施抛出。

更多信息请参见C#NullReferenceException和Null参数。

其他回答

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

实际上,修复NullReferenceExeption的最简单方法有两种。

例如,如果你有一个附带脚本的GameObject和一个名为rb(rigidbody)的变量,那么当你开始游戏时,这个变量将以null开头。这就是为什么会得到NullReferenceExeption,因为计算机中没有存储在该变量中的数据。

我将使用刚体变量作为示例。实际上,我们可以通过以下几种方式轻松地添加数据:

使用AddComponent>Physics>RigidBody将刚体添加到对象然后进入脚本并键入rb=GetComponent<Rigidbody>();这行代码在Start()或Awake()函数下最有效。您可以通过编程方式添加一个组件,同时用一行代码分配变量:rb=AddComponent<RigidBody>();

进一步注意:如果您希望Unity向您的对象添加组件,而您可能忘记添加组件,那么可以在类声明上方键入[RequireComponent(typeof(RigidBody))](所有using下方的空格)。

享受并享受制作游戏的乐趣!

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

例如:

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

虽然导致NullReferenceExceptions的原因和避免/修复此类异常的方法已经在其他答案中得到了解决,但许多程序员尚未学会的是如何在开发过程中独立调试此类异常。

在Visual Studio中,由于Visual Studio调试器,这通常很容易。


首先,确保将捕获正确的错误-请参见如何允许在VS2010中的“System.NullReferenceException”上中断?注释1

然后从调试开始(F5)或将[VS调试器]附加到正在运行的进程。有时,使用Debugger.Break可能很有用,它将提示启动调试器。

现在,当抛出(或未处理)NullReferenceException时,调试器将在发生异常的行上停止(记住上面设置的规则吗?)。有时错误很容易被发现。

例如,在下一行中,唯一可能导致异常的代码是myString求值为null。这可以通过查看观察窗口或在即时窗口中运行表达式来验证。

var x = myString.Trim();

在更高级的情况下,例如以下情况,您需要使用上述技术之一(观察或即时窗口)来检查表达式,以确定str1是否为null或str2是否为null。

var x = str1.Trim() + str2.Trim();

一旦找到了抛出异常的位置,通常很难反向推理,以找出空值被[错误]引入的位置--

花时间了解异常原因。检查空表达式。检查之前可能导致此类空表达式的表达式。根据需要添加断点并单步执行程序。使用调试器。


1如果“抛出时中断”过于激进,并且调试器在.NET或第三方库中的NPE上停止,则可以使用“用户未处理时中断”来限制捕获的异常。此外,VS2012还引入了Just My Code,我建议您也启用它。

如果您在启用“仅我的代码”的情况下进行调试,则行为略有不同。如果启用了“仅我的代码”,调试器将忽略在“我的代码外引发的、不通过“我的码”的第一次公共语言运行时(CLR)异常

请注意,无论情况如何,.NET中的原因总是相同的:

您正在尝试使用值为Nothing/null的引用变量。当引用变量的值为Nothing/null时,这意味着它实际上没有保存对堆上存在的任何对象实例的引用。您要么从未向变量赋值,要么从未创建分配给变量的值的实例,要么手动将变量设置为Nothing/null,要么为您调用了将变量设置成Nothing/nnull的函数。