在 C# 中,是否有一种干净的方法来检查多个级别的空引用

发布于 2024-09-19 10:54:07 字数 255 浏览 7 评论 0原文

例如,如果我想调用以下内容: person.Head.Nose.Sniff() 那么,如果我想安全,我必须执行以下操作:

if(person != null)
    if(person.Head != null)
        if(person.Head.Nose != null)
            person.Head.Nose.Sniff();

有没有更简单的方法来制定这个表达式?

For example, if I want to call the following:
person.Head.Nose.Sniff()
then, if I want to be safe, I have to do the following:

if(person != null)
    if(person.Head != null)
        if(person.Head.Nose != null)
            person.Head.Nose.Sniff();

Is there any easier way of formulating this expression?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

似最初 2024-09-26 10:54:07

首先,您可以利用布尔逻辑运算符中的短路并执行以下操作:

if (person != null && person.Head != null && person.Head.Nose != null)
{
    person.Head.Nose.Sniff();
}

另请注意,您所做的事情违反了开发软件的设计指南,该指南称为 德墨忒尔定律

First you can take advantage of short-circuiting in the boolean logic operators and do something like:

if (person != null && person.Head != null && person.Head.Nose != null)
{
    person.Head.Nose.Sniff();
}

Also note that what you are doing goes against a design guideline for developing software that is known as Law of Demeter.

幽梦紫曦~ 2024-09-26 10:54:07

有没有更简单的方法来表达这个表达式?

在 C# 6 中,您可以使用 null 条件运算符

代码示例

这是打包到方法中的原始代码,并假设 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 null 条件运算符重写的代码:

    public bool PerformNullCheckVersion2(Person person)
    {
        return person?.Head?.Nose?.Sniff() ?? false;
    }

< code>?? 是 空合并运算符 且与你的问题无关。

有关完整示例,请参阅:
https://github.com/lernkurve/Stackoverflow-question-3701563

Is there any easier way of formulating this expression?

With C# 6, you can use the null-conditional operator ?.

Code example

This is your original code packed into a method and assuming Sniff() always returns 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;
    }

This is your code rewritten with the C# 6 null-conditional operator:

    public bool PerformNullCheckVersion2(Person person)
    {
        return person?.Head?.Nose?.Sniff() ?? false;
    }

The ?? is the null-coalescing operator and is not related to your question.

For the full example, see:
https://github.com/lernkurve/Stackoverflow-question-3701563

玉环 2024-09-26 10:54:07

这是沿着同样提到的流畅参数验证的另一个实现:链式 null 检查和 Maybe monad

Here's another implementation along the lines of the also-mentioned Fluent Parameter Validation: Chained null checks and the Maybe monad

没企图 2024-09-26 10:54:07

其实也不是,除此之外

 if (person != null && person.Head != null && person.Head.Nose != null) 

Not really, besides

 if (person != null && person.Head != null && person.Head.Nose != null) 
把人绕傻吧 2024-09-26 10:54:07

您可以使用空对象而不是空值。如果调用链中的任何对象是空对象,则 Sniff 将不执行任何操作。

这不会引发异常:

person.Head.Nose.Sniff(); 

您的 null 类可能如下所示(您也可以将它们用作单例,并具有 IPersonIHeadINose 的接口code>):

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; 

You could use null objects instead of null values. Sniff would then do nothing if any objects in the call chain are null objects.

This would not throw an exception:

person.Head.Nose.Sniff(); 

Your null classes could look like this (you could also use them as singletons and have interfaces for IPerson, IHead and 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 */ }
}

As a side note, in Oxygene there's an operator for this:

person:Head:Nose:Sniff; 
滥情稳全场 2024-09-26 10:54:07

最好的方法是使用 && 运算符而不是嵌套的 if 语句:

if (person != null && person.Head != null && person.Head.Nose != null)
{
    person.Head.Nose.Sniff();
}

请注意,从技术上讲,您可以执行类似的 null 检查使用表达式树。你的方法将有一个像这样的签名:

static bool IsNotNull<T>(Expression<Func<T>> expression);

...这将允许你编写看起来像这样的代码:

if (IsNotNull(() => person.Head.Nose))
{
    person.Head.Nose.Sniff();
}

但这将涉及反射,并且与 < 相比,通常更难以以任何深入的方式遵循code>&& 方法。

The best way is just to use the && operator instead of nested if statements:

if (person != null && person.Head != null && person.Head.Nose != null)
{
    person.Head.Nose.Sniff();
}

Note that you technically could perform a similar null check using an expression tree. Your method would have a signature like this:

static bool IsNotNull<T>(Expression<Func<T>> expression);

...which would allow you to write code looking something like this:

if (IsNotNull(() => person.Head.Nose))
{
    person.Head.Nose.Sniff();
}

But this would involve reflection and would generally be much more difficult to follow in any sort of in-depth way compared to the && method.

盗梦空间 2024-09-26 10:54:07
if (person?.Head?.Nose != null) person.Head.Nose.Sniff();   
if (person?.Head?.Nose != null) person.Head.Nose.Sniff();   
本王不退位尔等都是臣 2024-09-26 10:54:07

我会摆脱对 null 的任何使用,并执行如下操作:

((Nose)person.BodyParts[BodyPart.Nose]).Sniff();

这将需要某种基本的类或接口。

public abstract class BodyPart
{
    public bool IsDecapitated { get; private set; }

    public BodyPart(bool isDecapitated)
    {
        IsDecapitated = isDecapitated;
    } 
}

I would get rid of any use of null and do something like this:

((Nose)person.BodyParts[BodyPart.Nose]).Sniff();

This would require some kind of base class or interface.

public abstract class BodyPart
{
    public bool IsDecapitated { get; private set; }

    public BodyPart(bool isDecapitated)
    {
        IsDecapitated = isDecapitated;
    } 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文