Исключение ловят не в том месте - PullRequest
1 голос
/ 30 марта 2019

У меня есть форма прогресса, которую я использую для выполнения задач, переданных ей асинхронно.В основном весь код формы:

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 голосов
/ 30 марта 2019

Разве вы не должны пытаться поймать 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();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...