昨天我在调试Windows窗体应用程序时发现了一个有趣的行为,请参考以下代码:
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子句中的任何对象空引用异常。
异常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时发生,否则它会起作用。
有谁知道异常的根本原因是什么以及为什么它与甚至尚未调用的Invoke方法有关?
答案 0 :(得分:1)
我理解的匿名方法存放在临时课程中。查看IL时,在进入方法的父范围时会调用临时类的ctor。
根据this article,当您使用周围的局部变量编译匿名方法时会发生以下情况:
a
被声明为匿名方法的临时类中的一个字段。在输入父作用域(在本例中为if语句)时调用构造函数,因此通过设置下一个语句,已跳过临时类的构造函数。
由于临时类现在为null,而a
是临时类中的一个字段,因此任何涉及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