Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A better way to handle NullReferenceExceptions in C#

I recently had a coding bug where under certain conditions a variable wasn't being initialized and I was getting a NullReferenceException . This took a while to debug as I had to find the bits of data that would generate this to recreate it the error as the exception doesn't give the variable name.

Obviously I could check every variable before use and throw an informative exception but is there a better (read less coding) way of doing this? Another thought I had was shipping with the pdb files so that the error information would contain the code line that caused the error. How do other people avoid / handle this problem?

Thanks

like image 324
probably at the beach Avatar asked Apr 12 '12 16:04

probably at the beach


5 Answers

Firstly: don't do too much in a single statement. If you have huge numbers of dereferencing operations in one line, it's going to be much harder to find the culprit. The Law of Demeter helps with this too - if you've got something like order.SalesClerk.Manager.Address.Street.Length then you've got a lot of options to wade through when you get an exception. (I'm not dogmatic about the Law of Demeter, but everything in moderation...)

Secondly: prefer casting over using as, unless it's valid for the object to be a different type, which normally involves a null check immediately afterwards. So here:

// What if foo is actually a Control, but we expect it to be String?
string text = foo as string;
// Several lines later
int length = text.Length; // Bang!

Here we'd get a NullReferenceException and eventually trace it back to text being null - but then you wouldn't know whether that's because foo was null, or because it was an unexpected type. If it should really, really be a string, then cast instead:

string text = (string) foo;

Now you'll be able to tell the difference between the two scenarios.

Thirdly: as others have said, validate your data - typically arguments to public and potentially internal APIs. I do this in enough places in Noda Time that I've got a utility class to help me declutter the check. So for example (from Period):

internal LocalInstant AddTo(LocalInstant localInstant,
                            CalendarSystem calendar, int scalar)
{
    Preconditions.CheckNotNull(calendar, "calendar");
    ...
}

You should document what can and can't be null, too.

like image 189
Jon Skeet Avatar answered Nov 17 '22 14:11

Jon Skeet


In a lot of cases it's near impossible to plan and account for every type of exception that might happen at any given point in the execution flow of your application. Defensive coding is effective only to a certain point. The trick is to have a solid diagnostics stack incorporated into your application that can give you meaningful information about unhandled errors and crashes. Having a good top-level (last ditch) handler at the app-domain level will help a lot with that.

Yes, shipping the PDBs (even with a release build) is a good way to obtain a complete stack trace that can pinpoint the exact location and causes of errors. But whatever diagnostics approach you pick, it needs to be baked into the design of the application to begin with (ideally). Retrofitting an existing app can be tedious and time/money-intensive.

like image 28
kprobst Avatar answered Nov 17 '22 13:11

kprobst


Sorry to say that I will always make a check to verify that any object I am using in a particular method is not null.

It's as simple as

if( this.SubObject == null )
{
    throw new Exception("Could not perform METHOD - SubObject is null.");
}
else
{
...
}

Otherwise I can't think of any way to be thorough. Wouldn't make much sense to me not to make these checks anyway; I feel it's just good practice.

like image 35
DigitalJedi805 Avatar answered Nov 17 '22 13:11

DigitalJedi805


First of all you should always validate your inputs. If null is not allowed, throw an ArgumentNullException.

Now, I know how that can be painful, so you could look into assembly rewriting tools that do it for you. The idea is that you'd have a kind of attribute that would mark those arguments that can't be null:

public void Method([NotNull] string name) { ...

And the rewriter would fill in the blanks...

Or a simple extension method could make it easier

name.CheckNotNull();
like image 20
Jordão Avatar answered Nov 17 '22 15:11

Jordão


If you are just looking for a more compact way to code against having null references, don't overlook the null-coalescing operator ?? MSDN

Obviously, it depends what you are doing but it can be used to avoid extra if statements.

like image 2
mafue Avatar answered Nov 17 '22 13:11

mafue