代码之家  ›  专栏  ›  技术社区  ›  Ivan-Mark Debono

在错误的位置捕获异常

  •  0
  • Ivan-Mark Debono  · 技术社区  · 6 年前

    我有一个进度表,用来执行异步传递给它的任务。基本上,表单的整个代码是:

    public ProgressForm(IEnumerable<KeyValuePair<string, Action>> tasks)
    {
        InitializeComponent();
        this.tasks = tasks;
    }
    
    protected override void OnShown(EventArgs e)
    {
        base.OnShown(e);
    
        PerformTasks(tasks);
    }
    
    private async void PerformTasks(IEnumerable<KeyValuePair<string, Action>> tasks)
    {
        tokenSource = new CancellationTokenSource();
        var token = tokenSource.Token;
    
        try
        {
            await Task.Run(() =>
            {
                foreach (var task in tasks)
                {
                    token.ThrowIfCancellationRequested();
                    task.Value();
                }
            }, token);
    
            isTaskCompleted = true;
        }
        catch (OperationCanceledException oex) when (oex.CancellationToken == token)
        { }
        catch
        {
            throw;
        }
        finally
        {
            tokenSource.Dispose();
            DialogResult = isTaskCompleted ? DialogResult.OK : DialogResult.Cancel;
            Close();
        }
    }
    

    然后,我调用表单,任务如下:

    try
    {
        using (var progress = new ProgressForm(() =>
        {
            SomeLongRunningTask();
        }))
        {
            progress.ShowDialog();
        };
    }
    catch (MyException ex)
    {
        //Do something
    }
    

    SomeLongRunningTask 引发类型为的异常 MyException .而不是被包围住 try/catch 块,它被主线程的异常处理捕获,即:

    [STAThread]
    static void Main()
    {
        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
    
        Application.Run();
    }
    
    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        //Do something
    }
    

    为什么异常没有在正确的位置被捕获,我如何才能使它在该块中被捕获?

    1 回复  |  直到 6 年前
        1
  •  0
  •   aybe    6 年前

    你不应该试着抓住 TaskCanceledException 相反呢?

    在下面的例子中,它是在最接近 try...catch 先封锁。

    应用程序:

    using System;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace temp
    {
        internal static class Program
        {
            [STAThread]
            private static void Main()
            {
                Application.ThreadException += ApplicationOnThreadException;
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
    
            private static void ApplicationOnThreadException(object sender, ThreadExceptionEventArgs e)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    形式:

    using System;
    using System.Media;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace temp
    {
        public partial class Form1 : Form
        {
            private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    
            public Form1()
            {
                InitializeComponent();
    
                var button1 = new Button {Text = "Start"};
                button1.Click += Button1OnClick;
    
                var button2 = new Button {Text = "Abort"};
                button2.Click += Button2OnClick;
    
                var panel = new FlowLayoutPanel();
                panel.Controls.Add(button1);
                panel.Controls.Add(button2);
    
                Controls.Add(panel);
            }
    
            private async void Button1OnClick(object sender, EventArgs e)
            {
                try
                {
                    var token = _cancellationTokenSource.Token;
    
                    await Task.Run(async () =>
                    {
                        for (var i = 0; i < 10; i++)
                        {
                            token.ThrowIfCancellationRequested();
    
                            await Task.Delay(3000, token);
    
                            SystemSounds.Beep.Play();
                        }
                    }, token);
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception);
                    throw;
                }
            }
    
            private void Button2OnClick(object sender, EventArgs e)
            {
                _cancellationTokenSource.Cancel();
            }
        }
    }