TLDR;
You get a NullReferenceException when your code is trying to use a null variable. You’re either calling a method on that variable or accessing a property or something else.
The problem is that there’s nothing to call upon to begin with. Either you have never assigned anything to that variable or you have set it to null yourself before trying to use it. Or some external code is returning a null to you, which you are not validating before you using it.
There are many reasons for this exception to pop up…
Example?
Look:
string whatever = null; whatever.ToCharArray(); // boom
This throws:
System.NullReferenceException: Object reference not set to an instance of an object.
See that? You can’t call ToCharArray() there because there’s no string instance to call upon in the first place. It’s a null. The house is there but the lights are off and there’s no one home.
How do I find it?
More often than not, the runtime will tell you what line exploded. That is, if you’re running your code in debug mode. If you get this error on production code, you will at the very least have the call stack included in the full error message. Use the call stack to navigate to the failing method in your code base. Then set a break point there and repeat the scenario that led the code to explode, running the code line-by-line from your breakpoint.
What should I watch out for and avoid?
Some coding anti-patterns are just asking for it.
Here are some examples of dodgyness to watch out for and ways to stamp it out.
Method Parameters
Nothing guarantees your method’s caller will provide all parameters…
static void Main() { string message = null; Log(message); } static void Log(string message) { var length = message.Length; // boom }
To avoid this, check for parameters you absolutely require and throw the ball back to the caller…
static void Log(string message) { if (message == null) { throw new ArgumentNullException("message"); } var length = message.Length; // boom }
Chaining Accessors
Look at this:
public class Car { public Engine Engine { get; set; } } public class Engine { public SparkPlug SparkPlug { get; set; } } public class SparkPlug { public void MakeSpark() { } } static void Main() { var car = new Car(); car.Engine.SparkPlug.MakeSpark(); // boom }
You’re chaining property getters without checking if any of those properties are null. Any of those gets can return null and acting upon the null will make things go boom.
You have different ways to avoid this situation.
If you enjoy typing, you can check for every single accessor…
if (car != null) { if (car.Engine != null) { if (car.Engine.SparkPlug != null) { car.Engine.SparkPlug.MakeSpark(); } } }
… but that’s a lot of typing.
Instead, you can short-circuit them in an if statement…
if (car != null && car.Engine != null && car.Engine.SparkPlug != null) { car.Engine.SparkPlug.MakeSpark(); }
… but that’s still a lot of typing.
If you’re not having to maintain some old code and you have at least C# 6, then you can use the safe navigation operator…
car?.Engine?.SparkPlug?.MakeSpark();
… which is great and tight, except you won’t know whether the MakeSpark() method was called or not.
Which is why you may want to go with this instead:
var sp = car?.Engine?.SparkPlug; if (sp != null) { sp.MakeSpark(); } else { // panic }
No Instance At All
When you declare a reference type member field, it has the default value of null, unless you say so otherwise.
private static string message; static void Main() { message.ToCharArray(); // boom }
Your defense here is the same as before.
if (message != null) { message.ToCharArray(); }
Using as Casting Operator
The as casting operator tests if casting is possible and returns null if not.
object whatever = "whatever"; // okay Car car = whatever as Car; // okay car.ToString(); // boom
Again, test for null.
object whatever = "whatever"; Car car = whatever as Car; if (car != null) { car.ToString(); }
Indexing
Arrays themselves are nullable objects.
If an array variable is null, there’s nothing to index.
Car[] cars = null; cars[0].ToString(); // boom
Sizing an array only makes space for its items.
It does not instantiate them, so are spots are null.
Car[] cars = new Car[10]; cars[0].ToString(); // boom
Jagged arrays are arrays in which each element references another array.
That reference is the same as any other reference, so it can be null.
If it’s null, there’s nothing to index.
Car[][] cars = new Car[10][]; cars[0][0] = new Car(); // boom
Lists and other indexable collections are no different.
If there is no instance, there’s nothing to index.
List<Car> cars = null; Car car = cars[0]; // boom
The solution to all of these is the same yet again.
Check for nulls before using anything.
foreach
If your enumeration is null, there is nothing to enumerate.
List<Car> cars = null; foreach (Car car in cars) // boom { }
You know what to do.
LINQ Expression
LINQ expressions don’t execute right away, so they don’t explode when you declare them.
Instead, they wait for you to call a materializer such as ToArray().
If your expression accesses null variables, it will go boom only when you execute it.
var cars = new List<Car>() { null }; var query = cars.Select(c => c.Engine); // c can be null var engines = query.ToArray(); // boom
To protect against this, you can check for nulls inside the projection, and even remove them if you want to.
var cars = new List<Car>() { null }; var query = cars.Select(c => c?.Engine).Where(e => e != null); var engines = query.ToArray();
Event Handlers
Event Handlers start out as null until someone attaches the first delegate to them.
If you use them before that, they go boom.
public class SparkPlug { public void MakeSpark() { OnSparkMade(EventArgs.Empty); } public event EventHandler SparkMade; protected virtual void OnSparkMade(EventArgs e) { SparkMade(this, e); // boom } } static void Main() { var sp = new SparkPlug(); sp.MakeSpark(); // boom }
Always test your event handlers before trying to execute their delegates.
protected virtual void OnSparkMade(EventArgs e) { if (SparkMade != null) { SparkMade(this, e); } }
Summary
Check for nulls all the time and you’ll be fine.