Introduction
Regarding to “NullReferenceException”, which is familiar to most of the programmers, because it is very likely to occur “NullReferenceException” when accessing a nested object property. For instance, opportunity.Contact.HomeAddress.Street, if any of the opportunity, Contact or HomeAddress is null, it throws “NullReferenceException”. This blog, will introduce you a easy extension method, which can void redundant chained null check, what’s more, it also can improve the readability of the code.
Chained null checks extensions
First, let’s take a look how to get “Street” in a normal way.
string street = null;
if (opportunity != null && opportunity.Contact != null && opportunity.Contact.HomeAddress != null)
{
street = opportunity.Contact.HomeAddress.Street;
}
This is still not too complex, but sometimes we need apply some business logic along with it:
string street = null;
if (opportunity != null && opportunity.Contact != null && opportunity.Contact.HomeAddress != null)
{
If(opportunity.Contact.HomeAddress.Street == null)
{
street = “Nanhuan Road, Hangzhou”;
}
else
{
street = opportunity.Contact.HomeAddress.Street;
}
}
Now it turns a little bit more complex and not that readable enough. What’s more, in the real project, the situation may double or more complex than this sample.
So, any ideas that can avoid so much is else statement and the null check? The answer is yes.
If you know F#, which is a functional programming language, I guess it should be very easy for you to understand the following solution. If you don’t have any experience with F#, don’t worry – because it is really very straightforward and easy for understanding.
In order to give you a feel to the chained null checks extensions, let’s rewrite above samples first.
string street = opportunity.With(o => o.Contact).With(c => c.HomeAddress).With(ha => ha.Street);
and
string street = opportunity.With(o => o.Contact).With(c => c.HomeAddress).With(ha => ha.Street).Return(s => s, "Nanhuan Road, Hangzhou");
Isn’t this brief and easy to understand?
Ok, now let’s take a little bit more time to look into these Extensions themselves.
With
Below is the definition of the With extension method.
public static TResult With<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
where TResult : class
where TInput : class
{
if (o == null)
{
return null;
}
return evaluator(o);
}
As you can see, if the input is null, then it return the value of the evaluator, which is a function/method provided by yourself. Take above rewrote samples for example,
opportunity.With(o => o.Contact)
“o => o.Contact” is the self-defined evaluator, which means get Contact property from o. So the meaning for “opportunity.With(o => o.Contact)” is, if opportunity is null, then return null, otherwise return Contact property value from opportunity.
Return
And for Return extension method.
public static TResult Return<TInput, TResult>(this TInput o,
Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
if (o == null)
{
return failureValue;
}
return evaluator(o);
}
Return extension has one more parameter than With extension – failure value.
opportunity.With(o => o.Contact).With(c => c.HomeAddress).With(ha => ha.Street).Return(s => s, “Nanhuan Road, Hangzhou”);
let’s split above statement to smaller ones.
opportunity.With(o => o.Contact) // return Contact property value from opportunity if opportunity is not null
With(c => c.HomeAddress) // return HomeAddress property value from contact if contact is not null
With(ha => ha.Street) // return Street property value from homeAddress if homeAddress is not null
Return(s => s, “Nanhuan Road, Hangzhou”); // return street property value if street is not null, otherwise return “Nanhuan Road, Hangzhou”
Attached “MaybeMonad.cs” is created by “Dmitri Nesteruk” and he had a good article in CodeProject have given more detailed introduction about this Chained null checks.
Reference: http://www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad