In C#, is there a clean way of checking for multiple levels of null references
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;
}
}
精彩评论