Fr33dan Fr33dan - 3 months ago 8
C# Question

Null reference exception when watching value in debugger works

I am overriding the equals function on a class of mine and am getting a null point exception despite the fact that when I enter the same code in the "watch" section of the debugger there is no exception.

Here is my code (anything compared with an

==
is a string or primitive type):

return this.workOrder == i.workOrder
&& this.upi == i.upi
&& this.testName == i.testName
&& BasicFunctions.ArraysEqual(this.testTrays, i.testTrays)
&& this.supplyVoltage == i.supplyVoltage
&& this.supplyAmperage == i.supplyAmperage
&& this.commandResults == null ? i.commandResults == null : this.commandResults.Equals(i.commandResults)
&& this.id == i.id;


The view from the watch window:
Screenshot of my watch window with one line for each section of the return statement. All but the supplyAmperage section are true.

The comparison of
commandResults
is the only thing that could result in a null exception and as you can see from the code this scenario should be handled by the ternary operator. Not only that but in the instances where it fails it should never have reached that section as the line should have stopped executing on the first false section. How can this be happening?

Edit:
As requested here are the details of the exception (note that this has be called by the ArrayEquals function and the exception is not inside the one used in the code listed)

System.NullReferenceException was unhandled
Message="Object reference not set to an instance of an object."
Source="ATE"
StackTrace:
at ATE.Network.TestLocationListener.TestClientInformation.Equals(Object obj) in C:\Users\jdudley\git\ATE\ATE\ATE\Network\TestLocationListener.cs:line 85
at ATE.BasicFunctions.ArraysEqual[T](T[] a1, T[] a2) in C:\Users\jdudley\git\ATE\ATE\ATE\BasicFunctions.cs:line 150
at ATE_Remote_Controller.Form1.remoteClient1_StatusUpdated(Object sender) in C:\Users\jdudley\git\ATE\ATE\ATE Remote Controller\Form1.cs:line 25
at ATE.Network.RemoteClient.statusRead(JSONReadCallbackResult res) in C:\Users\jdudley\git\ATE\ATE\ATE\Network\RemoteClient.cs:line 153
at ATE.Network.JSONReader.Receive(IAsyncResult ar) in C:\Users\jdudley\git\ATE\ATE\ATE\Network\JSONReader.cs:line 236
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
InnerException:

Answer

I think that what you have is equivalent to this

return this.workOrder == (i.workOrder
    && this.upi == i.upi
    && this.testName == i.testName
    && BasicFunctions.ArraysEqual(this.testTrays, i.testTrays)
    && this.supplyVoltage == i.supplyVoltage
    && this.supplyAmperage == i.supplyAmperage
    && this.commandResults == null) ? 
        i.commandResults == null : 
        (this.commandResults.Equals(i.commandResults)
        && this.id == i.id);

When what you want is this.

return this.workOrder == i.workOrder
    && this.upi == i.upi
    && this.testName == i.testName
    && BasicFunctions.ArraysEqual(this.testTrays, i.testTrays)
    && this.supplyVoltage == i.supplyVoltage
    && this.supplyAmperage == i.supplyAmperage
    && (this.commandResults == null ? 
        i.commandResults == null : 
        this.commandResults.Equals(i.commandResults))
    && this.id == i.id;

Basically if any of the previous statements are false, like this.supplyAmperage == i.supplyAmperage will cause the ternary operator to execute the this.commandResults.Equals(i.commandResults) even if this.commandResults is null.

Comments