Неправильное исключение - PullRequest
1 голос
/ 02 июля 2019

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

protected override void OnShown(object sender, EventArgs e)
{
    try
    {
        await Task.Run(() =>
        {
            //Run task here...
        });
    }
    catch (OperationCanceledException oex)
    { }
    catch
    { 
        throw;
    }
    finally
    {
        Close();
    }
}

И метод вызова:

try
{
    using (var progress = new ProgressForm(() =>
    {
        //The task to run async...
    }))
    {
        progress.ShowDialog();
    };
}
catch (MyCustomException cex)
{ }
catch (Exception ex)
{ }

A MyCustomException isброшенный задачей, поэтому форма прогресса просто отбрасывает ее.Однако обратно в вызывающий метод это исключение не перехватывается (перехватывается в блоке catch (Exception ex)), поскольку исключение, которое он получает из формы выполнения, каким-то образом TargetInvocationException, а его InnerException имеет тип MyCustomException.

Почему это происходит, и есть ли способ убедиться, что MyCustomException, выброшенный из формы выполнения, достигает вызывающего метода как есть?

Ответы [ 2 ]

1 голос
/ 02 июля 2019

Это сработало для меня:

try
{
    await Task.Run(() =>
    {
        //Run task here...
    });
}
catch (AggregateException ex)
{
    foreach (Exception inner in ex.InnerExceptions)
    {
         if (inner is MyCustomException)
         {
             //todo smt..
             throw inner;
         }
    }
}
0 голосов
/ 02 июля 2019

Может быть, вы можете реализовать свой ProgressForm таким образом, чтобы он отображался async, и дождаться его. Пример реализации может выглядеть так:

public class ProgressForm : Form
{
    private ProgressForm()
    {
    }

    public static async Task ShowAsync(Form owner, Action<IProgress<(string Message, int Progress)>> action)
    {
        owner.Enabled = false;
        try
        {
            using (var frm = new ProgressForm { StartPosition = FormStartPosition.CenterParent })
            {
                frm.Show(owner);

                try
                {
                    var progress = new Progress<(string Message, int Progress)>(frm.OnProgress);
                    await Task.Run(() => action(progress));
                }
                finally
                {
                    frm.Close();
                }
            }
        }
        finally
        {
            owner.Enabled = true;
        }
    }

    private void OnProgress((string Message, int Progress) args)
    {
        // Report progress to this ProgressForm here.
        // This line is only for demonstration. Please add controls to the form.
        this.Text = $@"{args.Message} {args.Progress}%";
    }
}

Пожалуйста, имейте в виду, что это вызовет Show вместо ShowDialog. Владелец отключен, поэтому он ведет себя как модальная форма (только для этого родителя!).

Использование может выглядеть следующим образом:

private async void button1_Click(object sender, EventArgs e)
{
    void DoSomeWork(IProgress<(string Message, int Progress)> progress = null)
    {
        var loops = 5;
        for (var i = 0; i < loops; ++i)
        {
            progress?.Report(($"Loop {i + 1}", (i + 1) * 100 / loops));
            Thread.Sleep(500);
        }

        throw new DivideByZeroException("...");
    }

    try
    {
        await ProgressForm.ShowAsync(this, DoSomeWork);
    }
    catch (DivideByZeroException)
    {
        MessageBox.Show("Yeah...");
    }
}

Надеюсь, это поможет.

Этот код выполняет Thread.Sleep в Task.Run! Это только демонстрация, и мне нужен образец, который требует времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...