例如,如果我想调用以下内容:
person.Head.Nose.Sniff()
那么,如果我想安全,我必须执行以下操作:
if(person != null)
if(person.Head != null)
if(person.Head.Nose != null)
person.Head.Nose.Sniff();
有没有更简单的方法来表达这个表达式?
例如,如果我想调用以下内容:
person.Head.Nose.Sniff()
那么,如果我想安全,我必须执行以下操作:
if(person != null)
if(person.Head != null)
if(person.Head.Nose != null)
person.Head.Nose.Sniff();
有没有更简单的方法来表达这个表达式?
首先,您可以利用布尔逻辑运算符中的短路并执行以下操作:
if (person != null && person.Head != null && person.Head.Nose != null)
{
person.Head.Nose.Sniff();
}
另请注意,您所做的事情违反了开发软件的设计指南,即Demeter 法则。
有没有更简单的方法来表达这个表达式?
在 C# 6 中,您可以使用空条件运算符 ?
。
这是您打包到方法中的原始代码,并假设Sniff()
总是返回true
:
public bool PerformNullCheckVersion1(Person person)
{
if (person != null)
if (person.Head != null)
if (person.Head.Nose != null)
return person.Head.Nose.Sniff();
return false;
}
这是用 C# 6 空条件运算符重写的代码:
public bool PerformNullCheckVersion2(Person person)
{
return person?.Head?.Nose?.Sniff() ?? false;
}
是??
空合并运算符,与您的问题无关。
有关完整示例,请参阅: https ://github.com/lernkurve/Stackoverflow-question-3701563
下面是另一个实现,与前面提到的 Fluent Parameter Validation 类似: Chained null checks and the Maybe monad
不是真的,除此之外
if (person != null && person.Head != null && person.Head.Nose != null)
您可以使用空对象而不是空值。Sniff
如果调用链中的任何对象都是空对象,则什么也不做。
这不会引发异常:
person.Head.Nose.Sniff();
您的 null 类可能如下所示(您也可以将它们用作单例并具有用于IPerson
,IHead
和的接口INose
):
class NullPerson : Person {
public override Head Head { get { return new NullHead(); }
}
class NullHead : Head {
public override Nose Nose { get { return new NullNose(); }
}
class NullNose : Nose {
public override void Sniff() { /* no-op */ }
}
作为旁注,在 Oxygene 中有一个操作符:
person:Head:Nose:Sniff;
您可以使用流畅的参数验证
最好的方法是使用&&
运算符而不是嵌套if
语句:
if (person != null && person.Head != null && person.Head.Nose != null)
{
person.Head.Nose.Sniff();
}
请注意,从技术上讲,您可以使用表达式树执行类似的空值检查。您的方法将具有如下签名:
static bool IsNotNull<T>(Expression<Func<T>> expression);
...这将允许您编写如下所示的代码:
if (IsNotNull(() => person.Head.Nose))
{
person.Head.Nose.Sniff();
}
但这将涉及反思,并且与该方法相比,通常更难以以任何深入的方式遵循&&
。
if (person?.Head?.Nose != null) person.Head.Nose.Sniff();
我会摆脱任何使用null
并做这样的事情:
((Nose)person.BodyParts[BodyPart.Nose]).Sniff();
这将需要某种基础class
或interface
.
public abstract class BodyPart
{
public bool IsDecapitated { get; private set; }
public BodyPart(bool isDecapitated)
{
IsDecapitated = isDecapitated;
}
}