Object reference not set to an instance of an object.Why doesn't .NET show which object is `null`?
(For information about the new exception helper in Visual Studio 2017 see the end of this answer)
Consider this code:
String s = null;
Console.WriteLine(s.Length);
This will throw a NullReferenceException
in the second line and you want to know why .NET doesn't tell you that it was s
that was null when the exception was thrown.
To understand why you don't get that piece of information you should remember that it is not C# source that executes but rather IL:
IL_0001: ldnull IL_0002: stloc.0 // s IL_0003: ldloc.0 // s IL_0004: callvirt System.String.get_Length IL_0009: call System.Console.WriteLine
It is the callvirt
opcode that throws the NullReferenceException
and it does that when the first argument on the evaluation stack is a null reference (the one that was loaded using ldloc.0
).
If .NET should be able to tell that it was s
that was a null reference it should in some way track that the first argument on the evaluation stack originated form s
. In this case it is easy for us to see that it is s
that was null but what if the value was a return value from another function call and not stored in any variable? Anyway, this kind of information is not what you want to keep track of in a virtual machine like the .NET virtual machine.
To avoid this problem I suggest that you perform argument null checking in all public method calls (unless of course you allow the null reference):
public void Foo(String s) {
if (s == null)
throw new ArgumentNullException("s");
Console.WriteLine(s.Length);
}
If null is passed to the method you get an exception that precisely describes what the problem is (that s
is null).
Four years later Visual Studio 2017 now has a new exception helper that will try to tell what is null when a NullReferenceException
is thrown. It is even able to give you the required information when it is the return value of a method that is null:
Note that this only works in a DEBUG build.
How do you want the error message in the following case look like?
AnyObject.GetANullObject().ToString();
private object GetANullObject()
{
return null;
}
No variable names to report here!