What happens if you throw null
?
I recently had this C# question come into my head:
You can throw an exception with something like
throw new ArgumentException()
, but what if you dothrow null;
instead?
I had to experiment and see.
Which of the following do you think will happen?
- It creates an error that can’t be caught, because no handler can catch
null
. - Nothing happens because no exception is provided to actually throw.
- A not-null exception is thrown.
All of these seemed plausible to me.
The program I used to test this was a simple:
throw null;
This actually gave me a compiler warning:
CS8597: Thrown value may be null.
That’s a warning, not an error. CS8597 really doesn’t have a lot of documentation online, but its description is pretty straightforward. It recognizes this as suspicious. But as a warning, I could still compile and run it.
So what happens? This code crashed! That immediately eliminates Option 2.
Then I saw the output:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object
at Program.<Main>$(String[] args) in C:\Users\RB\source\repos\Sandbox\Program.cs:line 1
That eliminates Option 1 as well.
The exception throwing mechanism isn’t expecting to get a null
value.
What does other code do when it is fed null
but null
isn’t allowed?
Other code throws a NullReferenceException
in this case.
That’s the same thing that happens here.
When the exception throwing mechanism is activated, if the exception given to it is actually null
, then it will throw a NullReferenceException
at that site instead.
And this exception is not special, but just a plain old NullReferenceException
.
If you have a catch (NullReferenceException)
, it will catch it.
Same with a catch (Exception)
.
For all practical purposes that I can see, it looks like throw null;
is functionally identical to throw new NullReferenceException();
, other than perhaps being a tiny bit slower.
(Though please don’t use throw null;
as a shorthand way to throw null reference exceptions!)
I don’t expect that there are many places where you’d attempt a direct throw null;
.
If I saw that in a pull request, I’d reject it.
It’s clearly not what you want.
I suspect scenarios where this actually happens are more subtle. Something more like:
throw MakeException("Kaboom!");
Exception? MakeException(string type)
{
return type switch
{
"Tick Tick Tick" => new ExplosionPendingException(),
"kaboom!" => new ExplosionException(),
_ => null
};
}
class ExplosionPendingException : Exception { }
class ExplosionException : Exception { }
This code will throw null
because the casing on those strings are not a match.
That is the real bug here, though seeing a NullReferenceException
isn’t going to immediately make you think to check that.
It looks extremely weird to me to see throw
without a new
immediately following it.
I almost never write code this way.
But I do occasionally see code along these lines, including in the Base Class Library.
So at least some C# programmers do occasionally write code like this.
Is CS8597 warning associated with the other nullability warnings?
There’s one final thing I wanted to try.
I got a compiler warning that I was potentially throwing null.
It got me wondering if I’d still see that warning if I didn’t have the Nullable
project setting enabled, which is intended to give you warnings when your code doesn’t appear to be handling null
or potential null
values correctly.
So I turned that project setting to Disabled
, and the warning went away.
(The behavior remained the same.)
I knew that the Nullable
project setting affected compiler warnings.
I don’t think I really grasped just how many flavors of warnings there are in this category.
It turns out that there’s about 40 of them, though on most days, there’s probably only about four flavors that I actually bump into.