Object reference not set to an instance of an object - how to find the offending object name in the exception?
This is the bane of my programming existence. After deploying an application, when this error crops up, no amount of debug dump tells you WHAT object was not instantiated. I have the call stack, that's great, it tells me roughly where the object is, but is there any way to get .NET to tell me the actual name of the object?
If you catch them while debugging, of course the program breaks right on the offend开发者_StackOverflowing creature, but if it happens after the program is in the wild, good luck.
There has to be a way.
I've explored the exceptions returned in these instances and there is just nothing helpful.
No, it's not possible. The exception happens because a reference is null, and references doesn't have names. Variables and class/struct members have names, but it's not certain that the reference is stored in either of those. The reference could for example be created like this:
someObject.GetInstance().DoSomething();
If the GetInstance
method returns null, there is a null reference exception when you try to use the reference to call DoSomething
. The reference is just a return value from the method, it's not stored in a variable, so there is nothing to get a name from.
If you have debugging information in the compiled assembly, you will get the line number in the stack trace in the exception, but that is as close as you can get.
NullReferenceException
is the most evil of all exceptions in an application. It means a possibly-null reference wasn't checked for a null value before it was accessed.
It's evil, because the runtime can't determine what you were expecting to find in the reference, so it can't tell you what precisely failed to be de-referenced.
The stack trace is your only friend in this exception, where it can at least identify which method threw the exception. If your code is neat enough, it should identify a small amount of code to check through.
Additionally, if you're running with a debug build and have the debugging information with the assemblies, you'll even get source line numbers in the stack trace, so you can know exactly what line the method failed on.
The real answer is to prevent this exception from ever being thrown. It's an indicator that some code was poorly written, failing to deal with the scenario where a reference was null
.
If you have a method being called where you need to do something with a reference-type argument that needs to be de-referenced at some point, check for null
and throw ArgumentNullException
, indicating the name of the parameter:
if(parameter == null)
throw new ArgumentNullException("parameter");
If you are performing an operation within a class and a settable property can be set to null
, check before de-referencing it and throw an InvalidOperationException
indicating the problem:
if(Property == null)
throw new InvalidOperationException("Property cannot be null.");
You should also make sure that all methods you're calling that can return reference types are guaranteed to return a value. For all those that are not, make similar checks for null
and handle the case appropriately.
EDIT:
To clarify, I'm not suggesting you perform a check on every reference-type variable before you de-reference it. That would be madness.
It's about understanding where a variable can be assigned null
and where it cannot. If you assign a private field in a class to a non-null value in the constructor, and the value is never assigned again, you don't need to check whether the value is null
; the design of your class has made sure it never can be.
A well-designed object will restrict the opportunities for null
values being assigned and will use guard code where appropriate to throw exceptions when a null
value can be present.
This is one of those instances where you really need to attach to the application and step through the general area of the offending code to figure out where that null reference is coming from.
I think currently the best you can get is the line no.
StackTrace:
at test_003.Form1.button1_Click(Object sender, EventArgs e) in C:\Documents and Settings\...\Projects\test_003\test_003\Form1.cs:line 52
If they do something in future about this problem, it would be great.
精彩评论