2010-11-21 38 views
2

我目前正试图以检查其是否使用带有“的MyMethod”之前一提的是空:C# - “对象引用不设置到对象的实例”

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

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

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

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

有没有更简单的方法来做到这一点?

+0

你如何填写School.ClassRoom数据?填充时,不允许NULL行可能是一个解决方案? – 2010-11-21 08:47:39

+0

顺便说一句,你的标题似乎并不合适。没有任何混淆你所得到的例外。 – 2010-11-21 09:13:48

+0

如果可能的话,我希望能够继续使用空类,因为这是一个相当复杂的数据结构的一部分,如果我开始有所有的空值的新实例,那么我认为内存使用率将通过屋顶。 – Caustix 2010-11-21 09:55:20

回答

5

这听起来像是你在类似Groovy的无效解引用操作符之后,它会让你编写if (School?.ClassRoom?.Pupil?.Age != null)--但是C#没有这样的东西。

恐怕你检查每个属性为无效,假设它可以空:

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

当然,你可以把这个整个if块包括方法调用本身一个辅助方法,然后调用它。

这就是假设它对每个属性有效,以 null开头。如果你能够设计你的类,那么甚至不允许使用空值 - 并且你在contsructors等中验证了这一点 - 你的代码很可能会变得更加干净。

值得注意的是,这里有两种替代方法 - 克里斯在另一个答案中提出的方法是为每个属性创建一个“默认”对象;我通常发现总是需要在构造函数中提供“真实”值更好。没有真实数据的默认对象最终会导致比NullReferenceException问题难以跟踪的错误,因为您可以长时间快乐地处理“虚拟”数据,并在最后得到错误的结果。当然,有些时候是正确的选择,但是 - 尤其是当涉及到收藏时。这取决于实际情况。

编辑:赛义德建议在评论中的扩展方法。我想这会是这样的:(适当调整类型)

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

我肯定更喜欢尝试让一切非空别处的想法,但如果你需要它,这将做到这一点。虽然我感觉不对。这种直觉的核心是你正在导航三个或四个属性 - 这对我来说就像是违反了Law of Demeter。现在我不是那种对这种事情有教条意义的人,但是在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.ClassRoom.Pupil.Age没有那么紧密的关系。

+0

他希望不要这样做,而不是'如果'写一个扩展方法 – 2010-11-21 09:00:10

+0

@Saeed:嗯,他在哪里提及扩展方法? – 2010-11-21 09:00:58

+1

if(School.IsNullAge())写这样一个函数很容易,他为什么要提这个,他不喜欢丑陋的代码 – 2010-11-21 09:02:45

1

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

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

这会给学校的空教室里下手,所以它不是null,不能设置为null外班的,因为物业没有一个二传手。你可以将这个概念向前推进,你的学生列表(我认为这将是一个列表)可以是一个空列表而不是空实例等。

1

“空对象模式”可以帮助你解决问题。阅读here

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

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

+0

那么它*可能*来救援。这取决于是否真的*是一个明智的“空”版本。正如我在答复中所写的,提供虚拟数据很容易导致难以诊断的问题。 – 2010-11-21 09:02:03

2

Here表达树是一个不错的和优雅的解决方案。 试试吧,尽情享受吧!

相关问题