开发者

In C#, is there a clean way of checking for multiple levels of null references

开发者 https://www.devze.com 2023-01-16 10:54 出处:网络
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:

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 easie开发者_Python百科r way of formulating this expression?


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.


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


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


Not really, besides

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


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; 


You can use Fluent Parameter Validation


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.


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


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;
    } 
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号