.NET WinForms 应用程序在退出时崩溃,并显示未处理的 System.NullReferenceExcepti

本文关键字:显示 未处理 NullReferenceExcepti System 崩溃 应用程序 WinForms 退出 NET | 更新日期: 2023-09-27 18:32:17

我有一个WinForms应用程序,其中包含一个带有后台工作线程的表单。 该窗体包含一个通过 RunWorkerAsync() 启动后台工作线程的按钮和另一个将退出应用程序的按钮。 大约 1/3 的时间,在后台工作线程完成其工作后,应用程序将在我单击退出按钮后崩溃,并出现如下异常:

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 相关句柄上调用关闭和释放方法。 该代码如下所示:

    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,所以我在追踪这个问题时遇到了麻烦。

对于它的价值,我的后台工作人员执行以下操作:

  1. 它从USB设备读取和写入一些数据
  2. 它创建一个Web客户端来下载一些数据
  3. 它进行一些 SOAP 调用

有没有人知道当应用程序(未显式使用 System.Drawing)退出时可能导致 System.Drawing 中未处理的 NullReferenceException 是什么?

.NET WinForms 应用程序在退出时崩溃,并显示未处理的 System.NullReferenceExcepti

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

很可能您的后台辅助角色尚未完成。另请注意,后台工作线程是与窗体的事件层次结构相关联的组件。

尝试创建新任务:

this.BeginInvoke(new Action(() => (Thread.Sleep(1000); this.Close();))); .

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

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

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

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