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

9

20

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?

Dorthadorthea answered 13/9, 2010 at 14:55 Comment(8)
Wouldn't every Person have a Head and every Head have a Nose automatically?Oculus
There are still places in the world where decapitation is practiced...Tiana
...in which case, Person would become Corpse.Oculus
..or just have its IsCorpse property turn trueTiana
To continue that rather macabre example, Person would need a Dispose method. Perhaps something like a wood chipper.Clotheshorse
This reminds me of Objective C. You can write [person.Head.Nose Sniff] right away without checking for nil value, though you never know if you have really Sniff it or not...Jonjona
You could use the Null Object Pattern also ... which would require every Person to have a Head even if it's not their own.Retro
See also haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx which discusses a proposal for a "null dereferencing operator".Retro
S
17

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

Sectorial answered 10/7, 2016 at 20:8 Comment(0)
L
19

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.

Lanoralanose answered 13/9, 2010 at 14:57 Comment(2)
Agreed. In this case I may think about creating a method person.Sniff() which call Head.Sniff() (if not null) which call Nose.Sniff() (if not null). In that way, you just have to check if person is not null and you minimize the knowledge to friends as designed in Law of Demeter.Hemangioma
"I'd prefer it to be called the Occasionally Useful Suggestion of Demeter." Martin Fowler haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspxRetro
S
17

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

Sectorial answered 10/7, 2016 at 20:8 Comment(0)
G
6

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

Graceless answered 13/9, 2010 at 15:19 Comment(0)
T
4

Not really, besides

 if (person != null && person.Head != null && person.Head.Nose != null) 
Tiana answered 13/9, 2010 at 14:57 Comment(0)
P
3

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; 
Petrous answered 13/9, 2010 at 15:11 Comment(2)
I thought about posting this answer... I just couldn't think of a good reason to have a null body part.Coxcombry
@ChaosPandion: LOL! This example is really bad for this discussion! Maybe a Default body part then, and never allow it to be null.Babarababassu
P
2

You can use Fluent Parameter Validation

Pycnometer answered 13/9, 2010 at 15:3 Comment(1)
That looks interesting. In vb.net, properties cannot be referenced without being read or written, so one could make change most of the validation methods to properties to ensure that the Check() was performed. Not sure if there's any way to do that in C. I don't like using methods or properties of null objects, but a static dummy instance should work just as well as "null". Incidentally, the system does allow one to define a generic class which inherits Exception; such classes can be thrown and caught. Further inheritance is a pain, but not impossible.Reagent
B
1

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.

Birkner answered 13/9, 2010 at 15:9 Comment(0)
J
1
if (person?.Head?.Nose != null) person.Head.Nose.Sniff();   
Jealous answered 21/6, 2021 at 14:27 Comment(1)
Why not person?.Head?.Nose?.Sniff(); ? (I think that'll work)Strikebreaker
C
0

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;
    } 
}
Coxcombry answered 13/9, 2010 at 15:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.