异常被放在错误的地方

时间:2019-03-30 03:33:47

标签: c# winforms

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

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 个答案:

答案 0 :(得分:0)

您不是应该尝试抓住TaskCanceledException吗?

在下面的示例中,它首先被捕获在最接近的try...catch块中。

app:

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