我有一些代码,当它执行时,它会抛出NullReferenceException,说:
对象引用未设置为对象的实例。
这意味着什么,我可以做什么来修复这个错误?
我有一些代码,当它执行时,它会抛出NullReferenceException,说:
对象引用未设置为对象的实例。
这意味着什么,我可以做什么来修复这个错误?
当前回答
更新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”)。而值类型始终包含值。
引用类型(必须选中这些类型):
动态对象一串
值类型(您可以忽略这些类型):
数字类型整数类型浮点类型十进制的布尔用户定义的结构
其他回答
实际上,修复NullReferenceExeption的最简单方法有两种。
例如,如果你有一个附带脚本的GameObject和一个名为rb(rigidbody)的变量,那么当你开始游戏时,这个变量将以null开头。这就是为什么会得到NullReferenceExeption,因为计算机中没有存储在该变量中的数据。
我将使用刚体变量作为示例。实际上,我们可以通过以下几种方式轻松地添加数据:
使用AddComponent>Physics>RigidBody将刚体添加到对象然后进入脚本并键入rb=GetComponent<Rigidbody>();这行代码在Start()或Awake()函数下最有效。您可以通过编程方式添加一个组件,同时用一行代码分配变量:rb=AddComponent<RigidBody>();
进一步注意:如果您希望Unity向您的对象添加组件,而您可能忘记添加组件,那么可以在类声明上方键入[RequireComponent(typeof(RigidBody))](所有using下方的空格)。
享受并享受制作游戏的乐趣!
关于“我该怎么办”的问题,可以有很多答案。
在开发时防止这种错误情况的一种更“正式”的方法是在代码中应用契约设计。这意味着在开发时,需要在系统上设置类不变量,和/或甚至函数/方法前置条件和后置条件。
简而言之,类不变量确保类中有一些约束在正常使用中不会被违反(因此,类不会处于不一致的状态)。前置条件意味着作为函数/方法输入的数据必须遵循某些约束集,并且永远不会违反这些约束,后置条件意味着函数/方法输出必须再次遵循这些约束集,而永远不会违反它们。在执行无错误程序期间,不应违反合同条件,因此,在调试模式下实际检查合同设计,而在发布版本中禁用,以最大化开发的系统性能。
通过这种方式,可以避免由于违反约束集而导致的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编程语言时创造的。
这意味着您的代码使用了一个设置为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
}
这意味着所讨论的变量没有指向任何对象。我可以这样生成:
SqlConnection connection = null;
connection.Open();
这将引发错误,因为虽然我声明了变量“connection”,但它没有指向任何对象。当我尝试将成员称为“Open”时,没有任何引用可供它解析,它会抛出错误。
要避免此错误,请执行以下操作:
在尝试对对象执行任何操作之前,请始终初始化对象。如果您不确定对象是否为空,请使用object==null进行检查。
JetBrains的ReSharper工具将识别代码中可能出现空引用错误的每个位置,从而允许您进行空检查。这个错误是错误的头号来源,IMHO。
当实体框架中使用的实体的类名与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