NullReferenceException when debugging and using invoke

回眸只為那壹抹淺笑 提交于 2020-04-16 05:15:31

问题


I found an interesting behavior yesterday while debugging a Windows Forms application, please refer to this code:

bool enter = false;

Debugger.Break(); 
if (enter) // Force to enter the if clause, read next comment
{
    bool a = false; // Bypass previous IF check in debug using 'Set Next Statment (CTRL-SHIFT-F10)' here
                    // Will throw null reference exception

    // If I don't use invoke everything works fine
    Invoke(new MethodInvoker(() =>
    {
        a = true;
    }));
}

So if I force to enter an IF clause that was not supposed to be entered in the method context, AND the code has an Invoke delegate that uses any object from within the IF clause it will throw a null reference exception.

Exception StackTrace:

   at WindowsFormsApplication2.Form1.Test() in c:\WindowsFormsApplication2\Form1.cs:line 26
   at WindowsFormsApplication2.Form1.Form1_Load(Object sender, EventArgs e) in c:\WindowsFormsApplication2\Form1.cs:line 16
   at System.Windows.Forms.Form.OnLoad(EventArgs e)
   at System.Windows.Forms.Form.OnCreateControl()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.WmShowWindow(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.ContainerControl.WndProc(Message& m)
   at System.Windows.Forms.Form.WmShowWindow(Message& m)
   at System.Windows.Forms.Form.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Seems like that the object was not even created in the method context, but it only happens when I have the Invoke, otherwise it will work.

Does anyone knows what is the root cause of the exception and why it is related to a Invoke method that wasn't even called yet?


回答1:


Anonymous methods to my understanding are housed in a temporary class. Looking at the IL the temporary class's ctor gets called when entering the parent scope of the method.

According to this article the following happens when you compile an anonymous method with a surrounding local variable:

  1. Create a new private class that is an inner class of the class where the anonymous method is defined.
  2. Create a public data member within the new class, with the same type and name as the local variable that is used in the anonymous method body.
  3. Create a public instance method within the new class that wraps the anonymous method.
  4. Replace the declaration of the local variable with the declaration of the new class. Create an instance of this new class in place of the declaration of the local variable.
  5. Replace the use of the local variable within the anonymous method body and outside the anonymous method, with the data member of the new class instance.
  6. Replace the anonymous method definition with the address of the instance method defined in the new class.

a is declared as a field within the anonymous method's temporary class. The constructor is invoked when entering the parent scope (in this case the if statement) so by setting the next statement, the constructor of the temporary class has been skipped.

Since the temporary class is now null, and a is a field on the temporary class, it makes sense that anything involving a causes a NullReferenceException.

.method private hidebysig instance void  button15_Click(object sender,
                                                        class [mscorlib]System.EventArgs e) cil managed
{
  // Code size       52 (0x34)
  .maxstack  4
  .locals init ([0] bool enter,
           [1] class WindowsFormsApplication1.Form1/'<>c__DisplayClass33' 'CS$<>8__locals34',
           [2] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  IL_0003:  call       void [mscorlib]System.Diagnostics.Debugger::Break()
  IL_0008:  nop
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.0
  IL_000b:  ceq
  IL_000d:  stloc.2
  IL_000e:  ldloc.2
  IL_000f:  brtrue.s   IL_0033
  IL_0011:  newobj     instance void WindowsFormsApplication1.Form1/'<>c__DisplayClass33'::.ctor()
  IL_0016:  stloc.1
  IL_0017:  nop
  IL_0018:  ldloc.1
  IL_0019:  ldc.i4.0
  IL_001a:  stfld      bool WindowsFormsApplication1.Form1/'<>c__DisplayClass33'::a
  IL_001f:  ldarg.0
  IL_0020:  ldloc.1
  IL_0021:  ldftn      instance void WindowsFormsApplication1.Form1/'<>c__DisplayClass33'::'<button15_Click>b__32'()
  IL_0027:  newobj     instance void [System.Windows.Forms]System.Windows.Forms.MethodInvoker::.ctor(object,
                                                                                                     native int)
  IL_002c:  call       instance object [System.Windows.Forms]System.Windows.Forms.Control::Invoke(class [mscorlib]System.Delegate)
  IL_0031:  pop
  IL_0032:  nop
  IL_0033:  ret
} // end of method Form1::button15_Click


来源:https://stackoverflow.com/questions/16060244/nullreferenceexception-when-debugging-and-using-invoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!