2

动机

Task在一个Windows.Forms应用程序中使用 a ,我想处理Task由 using引发的任何异常,Task.ContinueWith()Control.Invoke()在主 UI 线程上重新引发任何异常。

但是,如果我使用,我无法注意到异常Control.Invoke()- 但如果我使用Control.BeginInvoke().

有谁知道为什么它不工作Control.Invoke(),以及如何让它工作?

解决方法

我目前使用Control.BeginInvoke()的是 throw 而不是使用Control.Invoke()

重现步骤

环境:Windows 7 x64,Visual Studio 2012,为 .Net 4 编译(但 .Net 4.5 作为 VS2012 的一部分安装)。

(1) 使用名为form1.

(2) 在名为 的表单上放置一个按钮button1,并为其添加一个名为 的处理程序button1_Click()

(3) 执行button1_Click()如下:

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        this.BeginInvoke(new Action(() =>
        {
            throw new InvalidOperationException("TEST");
        }));
    });
}

(4) 运行程序并单击按钮。一秒钟后,将显示一个异常对话框,如您所料。

(5) 现在this.BeginInvoke改为this.Invoke

(6) 再次运行程序并单击按钮。现在异常被默默地忽略了!

两者都在指定的 UI 线程上执行Invoke(),所以我不明白为什么在一种情况下会忽略异常,而在另一种情况下不会忽略异常...BeginInvoke()Control

我猜这一定与Control.Invoke()如果它抛出异常就永远不会返回的事实有关,但是我的大脑很痛苦,试图弄清楚为什么这意味着异常(显然)被完全忽略了。

4

1 回答 1

3

This is by design, Invoke() handles exceptions differently than BeginInvoke(). It will marshal the exception back and re-throw it so that you know that the invoked method failed. This cannot work for BeginInvoke() since the thread has moved on already, so it is raised on the UI thread. The next problem is that the Task class swallows exceptions so you never see it.

You are doing this the hard way. If you like the default exception dialog then just use it with raising an exception at all:

this.BeginInvoke(new Action(() => {
    using (var dlg = new ThreadExceptionDialog(new InvalidOperationException("TEST"))) {
        dlg.ShowDialog();
        Environment.Exit(1);
    }
于 2013-03-29T14:13:26.970 回答