.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,所以我在追踪这个问题时遇到了麻烦。
对于它的价值,我的后台工作人员执行以下操作:
- 它从USB设备读取和写入一些数据
- 它创建一个Web客户端来下载一些数据
- 它进行一些 SOAP 调用
有没有人知道当应用程序(未显式使用 System.Drawing)退出时可能导致 System.Drawing 中未处理的 NullReferenceException 是什么?
尽管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),并浏览任何一行如果连续运行两次会失败的代码行。这可能会给你一个提示。