繁体   English   中英

C# - “对象引用未设置为对象的实例”

[英]C# - “Object reference not set to an instance of an object”

我正在尝试检查引用是否为空,然后'MyMethod'使用它:

if (School.ClassRoom.Pupil.Age != null)
        {
            MyMethod(School.ClassRoom.Pupil.Age);
        }

但是,我仍然在第一行得到“对象引用未设置为对象的实例”,因为不仅Age为null,而且Pupil和ClassRoom有时也为null。

我使用Try,Catch,最后得到了相同的问题,因为我在Try代码中遇到了同样的错误。

我不想要检查每个ClassRoom为null,然后每个Pupil为null,然后每次Age为null,每次我想使用此方法。

有更简单的方法吗?

注意:下面的答案是在2010年编写的,早在C#6中引入了null条件运算符之前。


听起来你像是在使用Groovy的null-safe dereferencing运算符,它会让你写if (School?.ClassRoom?.Pupil?.Age != null) - 但C#在C#6之前没有这样的东西。

我担心你必须检查每个属性是否 null,假设它可以 null:

if (School != null && School.ClassRoom != null && School.ClassRoom.Pupil != null
    && School.ClassRoom.Pupil.Age != null)
{
    MyMethod(School.ClassRoom.Pupil.Age);
}

当然,你可以将整个if包括方法调用本身的块放在一个帮助器方法中,然后调用它。

这是假设每个属性的有效开始时 null。 如果你能够设计你的类以便甚至不允许空值 - 并且你在contsructors等中验证它 - 你的代码可能最终变得更加清晰。

值得注意的是,这里有两种替代方法 - 克里斯在另一个答案中提出的方法是为每个属性创建一个“默认”对象; 通常发现总是要求在构造函数中提供“真实”值更好。 没有实际数据的默认对象最终会导致比NullReferenceException问题更难跟踪的错误,因为您可以很长时间地使用“虚拟”数据,并在最后得到错误的结果。 然而,肯定有时候这正确的事情 - 特别是在收藏方面。 这取决于实际情况。

编辑:Saeed在评论中提出了一种扩展方法。 我假设这将是这样的:

public static int? PupilAgeOrNull(this School school)
{
    return school != null && 
           school.ClassRoom != null && 
           school.ClassRoom.Pupil != null
           ? school.ClassRoom.Pupil.Age : null;
}

(适当调整类型。)

我绝对更喜欢尝试在其他地方保持非null值的想法,但如果你需要它会这样做。 但我感觉不对。 这种直觉的核心是你开始使用三到四个属性 - 这对我来说就像违反了得墨忒耳法 现在我不是一个会对这些事情发表教条的人,但是对于我这样一条长长的道路来说, School放一个延伸方法我来说太过具体了。

另一种选择 - IMO也有些讨厌 - 是编写三种不同的扩展方法:

public static ClassRoom ClassRoomOrNull(this School school)
{
    return school == null ? null : school.ClassRoom;
}

public static Pupil PupilOrNull(this ClassRoom classRoom)
{
    return classRoom == null ? null : classRoom.Pupil;
}

public static int? AgeOrNull(this Pupil pupil)
{
    return pupil == null ? null : pupil.Age;
}

然后你可以写:

int? age = School.ClassRoomOrNull().PupilOrNull().AgeOrNull();
if (age != null)
{
    MyMethod(age);
}

这意味着School的扩展方法并不是那么具体。 你仍然有很长的方法调用,我仍然会尝试重新设计以避免这种情况,如果可能的话,但至少从SchoolSchool没有这么紧密的关系School.ClassRoom.Pupil.Age

Expression Trees的一个漂亮而优雅的解决方案。 试试看吧!

给出你展示的代码,没有更简单的方法。 您需要检查每个组件。

if (School != null && School.ClassRoom != null 
  && School.ClassRoom.Pupil != null 
  && School.ClassRoom.Pupil.Age != null) 
{
  ...
}

但是,您可以编写代码,使成员永远不为null 这样你就可以避免检查null 例如

class School
{
  private ClassRoom _classRoom = new ClassRoom();

  public ClassRoom ClassRoom 
  {
    get {return _classRoom;}
  }
}

这将为School提供一个空的课堂空间,因此它不是null ,因为该属性没有setter,所以不能在类之外设置为null 你可以向前推进这个概念,你的学生列表(我假设这将是一个列表)可以是一个空列表而不是一个空实例等。

“空对象模式”来拯救你。 在这里阅读

所以,你可以有NullSchool,NullClassRoom,NullPupil,NullAge。

然后你永远不需要检查null的东西,而是你可以在MyMethod中只有一个检查(或方法,如Age类中的IsValid(),ofcourse virtual)以拒绝年龄,如果它无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM