This question already has an answer here:
Suppose, I have this interface,
interface IContact
{
IAddress address { get; set; }
}
interface IAddress
{
string city { get; set; }
}
class Person : IPerson
{
public IContact contact { get; set; }
}
class test
{
private test()
{
var person = new Person();
if (person.contact.address.city != null)
{
//this will never work if contact is itself null?
}
}
}
Person.Contact.Address.City != null
(This works to check if City is null or not.)
However, this check fails if Address or Contact or Person itself is null.
Currently, one solution I could think of was this:
if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{
// Do some stuff here..
}
Is there a cleaner way of doing this?
I really don't like the null
check being done as (something == null)
. Instead, is there another nice way to do something like the something.IsNull()
method?
Do it in a separate
method
like:Where your
IsNull
method
isOne way to remove null checks in methods is to encapsulate their functionality elsewhere. One way to do this is through getters and setters. For instance, instead of doing this:
Do this:
Then, whenever you call "person.contact", the code in the "get" method will run, thus initializing the value if it is null.
You could apply this exact same methodology to all of the properties that could be null across all of your types. The benefits to this approach are that it 1) prevents you from having to do null checks in-line and it 2) makes your code more readable and less prone to copy-paste errors.
It should be noted, however, that if you find yourself in a situation where you need to perform some action if one of the properties is null (i.e. does a Person with a null Contact actually mean something in your domain?), then this approach will be a hindrance rather than a help. However, if the properties in question should never be null, then this approach will give you a very clean way of representing that fact.
--jtlovetteiii
Your code may have bigger problems than needing to check for null references. As it stands, you are probably violating the Law of Demeter.
The Law of Demeter is one of those heuristics, like Don't Repeat Yourself, that helps you write easily maintainable code. It tells programmers not to access anything too far away from the immediate scope. For example, suppose I have this code:
The
DoAnAction
method violates the Law of Demeter. In one function, it accesses aBusinessCalcualtor
, aBusinessData
, and adecimal
. This means that if any of the following changes are made, the line will have to be refactored:BusinessCalculator.CalculateMoney()
changes.BusinessData.Money
changesConsidering the situation at had, these changes are rather likely to happen. If code like this is written throughout the codebase, making these changes could become very expensive. Besides that, it means that your
BusinessController
is coupled to both theBusinessCalculator
and theBusinessData
types.One way to avoid this situation is rewritting the code like this:
Now, if you make either of the above changes, you only have to refactor one more piece of code, the
BusinessCalculator.CalculateCents()
method. You've also eliminatedBusinessController
's dependency onBusinessData
.Your code suffers from a similar issue:
If any of the following changes are made, you will need to refactor the main method I wrote or the null check you wrote:
IPerson.contact
changesIContact.address
changesIAddress.city
changesI think you should consider a deeper refactoring of your code than simply rewriting a null check.
That said, I think that there are times where following the Law of Demeter is inappropriate. (It is, after all, a heuristic, not a hard-and-fast rule, even though it's called a "law.")
In particular, I think that if:
ignoring the Law of Demeter is acceptable when dealing specifically with those classes. This is because they represent the data your application works with, so reaching from one data object into another is a way of exploring the information in your program. In my example above, the coupling caused by violating the Law of Demeter was much more severe: I was reaching all the way from a controller near the top of my stack through a business logic calculator in the middle of the stack into a data class likely in the persistence layer.
I bring this potential exception to the Law of Demeter up because with names like
Person
,Contact
, andAddress
, your classes look like they might be data-layer POCOs. If that's the case, and you are extremely confident that you will never need to refactor them in the future, you might be able to get away with ignoring the Law of Demeter in your specific situation.The second question,
could be solved using an extension method:
Such a reference chain may occurre for example if you use an ORM tool, and want to keep your classes as pure as possible. In this scenario I think it cannot be avoided nicely.
I have the following extension method "family", which checks if the object on which it's called is null, and if not, returns one of it's requested properties, or executes some methods with it. This works of course only for reference types, that's why I have the corresponding generic constraint.
These methods add almost no overhead compared to the manual solution (no reflection, no expression trees), and you can achieve a nicer syntax with them (IMO).
Or with methods:
However, one could definetely argue about the length of code didn't change too much.
A totally different option (which I think is underused) is the null object pattern. It's hard to tell whether it makes sense in your particular situation, but it might be worth a try. In short, you will have a
NullContact
implementation, aNullAddress
implementation and so on that you use instead ofnull
. That way, you can get rid of most of the null checks, of course at the expense at some thought you have to put into the design of these implementations.As Adam pointed out in his comment, this allows you to write
in cases where it is really necessary. Of course, this only makes sense if city really is a non-trivial object...
Alternatively, the null object can be implemented as a singleton (e.g., look here for some practical instructions concerning the usage of the null object pattern and here for instructions concerning singletons in C#) which allows you to use classical comparison.
Personally, I prefer this approach because I think it is easier to read for people not familiar with the pattern.