Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET WinForms应用程序在退出时崩溃,系统未经处理。NullReferenceException_C#_.net_Winforms_Backgroundworker_Unhandled Exception - Fatal编程技术网

C# .NET WinForms应用程序在退出时崩溃,系统未经处理。NullReferenceException

C# .NET WinForms应用程序在退出时崩溃,系统未经处理。NullReferenceException,c#,.net,winforms,backgroundworker,unhandled-exception,C#,.net,Winforms,Backgroundworker,Unhandled Exception,我有一个WinForms应用程序,它包含一个带有后台工作程序的表单。表单包含一个通过RunWorkerAsync()启动后台工作程序的按钮和另一个将退出应用程序的按钮。大约有三分之一的时间,在后台工作人员完成其工作后,在我单击退出按钮后,应用程序将崩溃,例外情况如下: System.NullReferenceException was unhandled Message=Object reference not set to an instance of an object. Sourc

我有一个WinForms应用程序,它包含一个带有后台工作程序的表单。表单包含一个通过RunWorkerAsync()启动后台工作程序的按钮和另一个将退出应用程序的按钮。大约有三分之一的时间,在后台工作人员完成其工作后,在我单击退出按钮后,应用程序将崩溃,例外情况如下:

System.NullReferenceException was unhandled
  Message=Object reference not set to an instance of an object.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Graphics.Dispose(Boolean disposing)
       at System.Drawing.Graphics.Finalize()
以下是退出应用程序的按钮的事件处理程序:

    private void buttonExit_Click(object sender, EventArgs e)
    {
        if (!buttonStartWorker.Enabled)
        {
            DialogResult dr = MessageBox.Show("Background worker is still running!  Exit anyway?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (dr == DialogResult.OK)
            {
                backgroundWorker.CancelAsync();
                Close();
            }
        }
        else
        {
            Close();
        }
    }
如前所述,我不会在后台工作程序仍在运行时退出应用程序,因此我们在这里看到的代码路径只是Close()调用。还有一个FormClosing事件处理程序,它在我的USB相关句柄上调用close和dispose方法。该守则如下:

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        try
        {
            // close and dispose all open handles to the USB device
            if (hidHandle != null)
            {
                if (!(hidHandle.IsInvalid))
                {
                    hidHandle.Close();
                    hidHandle.Dispose();
                }
            }

            if (readHandle != null)
            {
                if (!(readHandle.IsInvalid))
                {
                    readHandle.Close();
                    readHandle.Dispose();
                }
            }

            if (writeHandle != null)
            {
                if (!(writeHandle.IsInvalid))
                {
                    writeHandle.Close();
                    writeHandle.Dispose();  // unhandled exception seems to occur after this
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }
在writeHandle.Dispose()和应用程序实际退出之间的某个时间,会发生此异常。最让我困惑的是,我的代码从来没有明确使用System.Drawing,所以我很难找到它

值得一提的是,我的背景工作者做了以下工作:

  • 它向USB设备读写数据
  • 它创建一个web客户端来下载一些数据
  • 它会进行一些SOAP调用

  • 有人知道是什么原因导致System.Drawing中出现未处理的NullReferenceException吗?当应用程序(不显式使用System.Drawing)退出时进行绘图?

    而您的程序可能不使用System。显式绘图时,大多数WinForms对象代码中都存在该命名空间。似乎在表单的某个地方,一个GUI对象被赋予了对另一个对象的图形句柄的引用,然后它认为必须销毁该句柄;但是,拥有该句柄的控件已被释放,或者图形对象本身已显式调用其Dispose方法,因此Dispose()代码在第二次运行时失败。我本希望.NET开发人员进行检查,以确保双重处置不会成为问题,但在本例中,他们似乎忽视了这一点

    如果不知道您的windows窗体上到底有什么,也不知道System.Drawing.Graphics的哪个实例被丢弃了,我真的无法进一步提供帮助。那将是我进一步调查的地方;尝试发现正在被释放的确切实例、拥有它的其他对象以及为什么在已经被释放后它会被最终确定(通常,如果显式地被释放,则应该调用GC.SuppressFinalize()


    其中一个“反射的”代码库引用可能会帮助您;查找System.Drawing.Graphics.Dispose(bool disposing),并浏览如果连续运行两次会失败的任何代码行。这可能会给你一个提示。

    尽管基思的答案原则上是正确的,但你的代码似乎确实存在一个明显的问题。您正在调用
    this.Close()在调用CancelAsync()之后。我会尝试等待后台工作人员完成其业务,或者订阅已取消的事件(如果存在)

    很可能您的后台工作人员尚未完成。还请注意,后台工作程序是一个与窗体的事件继承人权限相关联的组件

    尝试创建新任务:

    this.BeginInvoke(新操作(()=>(Thread.Sleep(1000);this.Close();))


    很抱歉语法不正确,但我不在开发人员机器上。

    发布完整的堆栈跟踪,请接受建议,Raheel。对于在CancelAsync()之后立即调用Close()的代码路径,您肯定提出了一个有效的观点。不幸的是,这不是我到目前为止一直在执行的代码路径。后台工作程序仍在运行时,我尚未关闭应用程序。在我的backgroundWorker\u RunWorkerCompleted()方法(此处未显示)中,我将buttonStartWorker.Enabled设置为true,这将导致buttonNexit\u Click()中的else子句被执行。我通过在buttonExit\u Click()的第一行上放置断点来验证这一点。