注:下面的答案写于 2010 年,早在空条件C# 6 中引入了运算符。
听起来您正在寻找类似 Groovy 的空安全解引用运算符之类的东西,它可以让您编写if (School?.ClassRoom?.Pupil?.Age != null)
- 但 C# 在 C# 6 之前没有这样的东西。
我怕你have检查每个属性是否无效,假设它可以be null:
if (School != null && School.ClassRoom != null && School.ClassRoom.Pupil != null
&& School.ClassRoom.Pupil.Age != null)
{
MyMethod(School.ClassRoom.Pupil.Age);
}
当然,你可以把这整个if
块将方法调用本身包含在辅助方法中,然后调用它。
假设每个属性都有效be开头为空。如果您能够设计您的类,甚至不允许空值 - 并且您在构造函数等中验证这一点 - 您的代码最终可能会变得更加干净。
值得注意的是,这里有两种替代方法 - Chris 在另一个答案中提出的方法是为每个属性创建一个“默认”对象;我usually发现最好始终要求在构造函数中提供“真实”值。没有真实数据的默认对象最终可能会导致错误,这些错误比错误更难追踪NullReferenceException
问题,因为您可以愉快地长期使用“虚拟”数据,但最终得到错误的结果。肯定有这样的时候is然而,这是正确的做法——尤其是在收藏方面。这取决于实际情况。
编辑:萨伊德在评论中建议了一种扩展方法。我认为这会是这样的:
public static int? PupilAgeOrNull(this School school)
{
return school != null &&
school.ClassRoom != null &&
school.ClassRoom.Pupil != null
? school.ClassRoom.Pupil.Age : null;
}
(适当调整类型。)
我绝对更喜欢尝试在其他地方保持非空值的想法,但是如果您需要它,这将做到这一点。但我感觉不对。这种直觉的核心是你一开始就在浏览三到四个属性——这感觉像是违反了德墨忒耳定律 http://en.wikipedia.org/wiki/Law_of_Demeter大部头书。现在我不是一个对这些事情教条的人,而是放置一个扩展方法on School
对于这么长的属性路径,我感觉太具体了。
另一种选择 - 在我看来也有点令人讨厌 - 是编写三种不同的扩展方法:
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
to School.ClassRoom.Pupil.Age
.