调试和使用调用时发生NullReferenceException [英] NullReferenceException when debugging and using invoke

查看:274
本文介绍了调试和使用调用时发生NullReferenceException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

昨天我在调试Windows Forms应用程序时发现了一个有趣的行为,请参考以下代码:

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;
    }));
}

因此,如果我强制输入不应在方法上下文中输入的IF子句,则 AND 该代码具有一个Invoke委托,该委托将使用IF子句中的任何对象空引用异常.

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.

异常StackTrace:

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)

似乎该对象甚至没有在方法上下文中创建,但是只有在我拥有Invoke时才会发生,否则它将起作用.

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.

有人知道异常的根本原因是什么,为什么它与尚未被调用的Invoke方法相关?

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?

推荐答案

据我了解,匿名方法位于一个临时类中.查看IL,进入方法的父范围时,将调用临时类的ctor.

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. 创建一个新的私有类,该私有类是定义匿名方法的类的内部类.
  2. 在新类中创建一个公共数据成员,其类型和名称与在匿名方法主体中使用的本地变量相同.
  3. 在包装匿名方法的新类中创建一个公共实例方法.
  4. 将局部变量的声明替换为新类的声明.创建这个新类的实例 代替声明局部变量.
  5. 使用数据成员替换匿名方法主体内部和匿名方法外部的局部变量的使用 新的类实例.
  6. 将匿名方法定义替换为新类中定义的实例方法的地址.
  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被声明为匿名方法的临时类中的字段.进入父作用域(在本例中为if语句)时,调用构造函数,因此通过设置下一条语句,已跳过了临时类的构造函数.

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.

由于临时类现在为空,并且a是临时类上的字段,所以任何涉及a的原因都会导致NullReferenceException.

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

这篇关于调试和使用调用时发生NullReferenceException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆