如何使用 Control.Invoke() 抛出一个不会被忽略的异常? [英] How can I use Control.Invoke() to throw an exception that won't be ignored?

查看:46
本文介绍了如何使用 Control.Invoke() 抛出一个不会被忽略的异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

动机

我在 Windows.Forms 应用程序中使用 Task,我想在其中使用 Task 处理任何由 Task 抛出的异常code>Task.ContinueWith() 和 Control.Invoke() 在主 UI 线程上重新抛出任何异常.

I'm using a Task in a Windows.Forms application where I want to handle any exceptions thrown by the Task by using Task.ContinueWith() and Control.Invoke() to rethrow any exceptions on the main UI thread.

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

However, I couldn't get the exception to be noticed if I use Control.Invoke() - but it works if I use Control.BeginInvoke().

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

Does anyone know why it doesn't work with Control.Invoke(), and how to get it to work?

解决方法

我目前使用 Control.BeginInvoke() 来抛出而不是使用 Control.Invoke()

I'm currently using Control.BeginInvoke() to throw instead of using Control.Invoke()

重现步骤

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

ENVIRONMENT: Windows 7 x64, Visual Studio 2012, Compiled for .Net 4 (but .Net 4.5 is installed as part of VS2012).

(1) 使用名为 form1 的表单创建一个默认的 Windows 窗体应用程序.

(1) Create a default Windows Forms app with a form called form1.

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

(2) Put a button on the form called button1, and add a handler for it called 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) 运行程序并单击按钮.一秒钟后,如您所料,将显示一个异常对话框.

(4) Run the program and click the button. After a second, an exception dialog is displayed as you would expect.

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

(5) Now change this.BeginInvoke to this.Invoke.

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

(6) Run the program again and click the button. Now the exception is silently ignored!

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

Both Invoke() and BeginInvoke() execute on the UI thread for the specified Control, so I can't understand why in one case the exception is ignored and in the other it is not ignored...

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

I'm guessing it must be something to do with the fact that Control.Invoke() will never return if it throws an exception, but my brain hurts trying to work out why that would mean the exception is (apparently) totally ignored.

推荐答案

这是设计使然,Invoke() 处理异常的方式与 BeginInvoke() 不同.它将封送异常并重新抛出它,以便您知道调用的方法失败.这对 BeginInvoke() 不起作用,因为线程已经移动了,所以它在 UI 线程上被引发.下一个问题是 Task 类吞下了异常,所以你永远看不到它.

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);
    }

这篇关于如何使用 Control.Invoke() 抛出一个不会被忽略的异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆