这听起来像是你在类似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
扩展方法并不是那么具体。你仍然有一长串的方法调用,我仍然试图重新设计,以尽可能避免这种情况,但至少从School
到School.ClassRoom.Pupil.Age
没有那么紧密的关系。
你如何填写School.ClassRoom数据?填充时,不允许NULL行可能是一个解决方案? – 2010-11-21 08:47:39
顺便说一句,你的标题似乎并不合适。没有任何混淆你所得到的例外。 – 2010-11-21 09:13:48
如果可能的话,我希望能够继续使用空类,因为这是一个相当复杂的数据结构的一部分,如果我开始有所有的空值的新实例,那么我认为内存使用率将通过屋顶。 – Caustix 2010-11-21 09:55:20