gpt4 book ai didi

c# - Object Disposed异常与多线程应用

转载 作者:太空狗 更新时间:2023-10-29 22:24:41 25 4
gpt4 key购买 nike

我有一个启动 System.Threading.Timer 的应用程序,然后这个计时器每 5 秒从链接的数据库中读取一些信息并在应用程序的主要形式上更新 GUI;

由于 System.Threading.Timer 为 Tick 事件创建了另一个线程,我需要使用 Object.Invoke 来更新应用程序主窗体上的用户界面,代码如下:

this.Invoke((MethodInvoker)delegate()
{
label1.Text = "Example";
});

该应用程序运行良好,但有时当用户关闭主窗体然后关闭应用程序时,如果 timer_tick 事件的第二个线程正在更新主线程上的用户界面,则用户会收到 ObjectDisposedException。

如何在关闭主窗体之前停止并关闭线程计时器并避免对象处理异常?

最佳答案

这是一个有点棘手的命题,因为您必须确保在给定的 Close 事件中满足以下条件

  1. 计时器停止。这是相当简单的
  2. 正在更新的控件不会在委托(delegate)运行时被释放。再次直截了当。
  3. 当前运行计时器滴答的代码已经完成。这更难但可行
  4. 没有待处理的 Invoke 方法。这很难完成

我以前遇到过这个问题,我发现防止这个问题是非常有问题的,并且涉及很多困惑、难以维护的代码。捕获这种情况下可能出现的异常要容易得多。通常,我通过如下方式包装 Invoke 方法来实现此目的

static void Invoke(ISynchronizedInvoke invoke, MethodInvoker del) {
try {
invoke.Invoke(del,null);
} catch ( ObjectDisposedException ) {
// Ignore. Control is disposed cannot update the UI.
}
}

如果您对后果感到满意,那么忽略此异常本质上没有错。也就是说,如果您对 UI 在处理后不更新感到满意。我当然是 :)

虽然上面没有解决问题 #2,它仍然需要在您的委托(delegate)中手动完成。在使用 WinForms 时,我经常使用以下重载来删除该手动检查。

static void InvokeControlUpdate(Control control, MethodInvoker del) {
MethodInvoker wrapper = () => {
if ( !control.IsDisposed ) {
del();
}
};
try {
control.Invoke(wrapper,null);
} catch ( ObjectDisposedException ) {
// Ignore. Control is disposed cannot update the UI.
}
}

注意

正如 Hans 所指出的,ObjectDisposedException 并不是唯一可以从 Invoke 方法中引发的异常。还有其他几个问题,至少包括您需要考虑处理的 InvalidOperationException

关于c# - Object Disposed异常与多线程应用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3641147/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com