[英]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
的扩展方法并不是那么具体。 你仍然有很长的方法调用,我仍然会尝试重新设计以避免这种情况,如果可能的话,但至少从School
到School
没有这么紧密的关系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.