C# 如何在没有块 UI 的情况下使用等待捕获任务中的异常

C# How to catch exception in a Task without block UI using wait

我在单击按钮时有此代码

private async void btnStart_Click(object sender, EventArgs e)
    {
        Msg.Clear();
        stopWatch.Reset();
        timer.Start();
        stopWatch.Start();
        lblTime.Text = stopWatch.Elapsed.TotalSeconds.ToString("#");
        progressBar.MarqueeAnimationSpeed = 30;
        try
        {
            await Task.Factory.StartNew(() =>
             {
                 try
                 {
                     Reprocess();
                 }
                 catch (Exception ex)
                 {
                     Msg.Add(new clsMSG(ex.Message, "Error", DateTime.Now));
                     timer.Stop();
                     stopWatch.Stop();
                     throw;
                 }
             });
        }
        catch
        {
            throw;
        }
    }

以及 Reprocess 方法

private void Reprocess()
    {
        try
        {
            clsReprocess reprocess = new clsReprocess(tbBD.Text, dtpStart.Value, 50000);
            reprocess.Start(reprocess.BD);
        }
        catch
        {
            throw;
        }
    }

Reprocess方法失败时,Task去catch,但是throw失败(throw inside catch(Exception ex)),UI阻塞,直到reprocess.Start方法完成。 我有两个问题:

希望你能理解我,抱歉我的英语不好。

你不应该使用 Task.Factory.StartNewTask.Run 写起来既安全又短。

此外,您只能从 UI 线程访问 UI 控件。如果 Msg 数据绑定到 UI,这可能是您所看到的问题的原因。即使不是,您也不想从多个线程访问不受保护的集合(例如,List<clsMSG>)。

同时应用这两个准则可将代码缩减为:

private async void btnStart_Click(object sender, EventArgs e)
{
  Msg.Clear();
  stopWatch.Reset();
  timer.Start();
  stopWatch.Start();
  lblTime.Text = stopWatch.Elapsed.TotalSeconds.ToString("#");
  progressBar.MarqueeAnimationSpeed = 30;
  try
  {
    await Task.Run(() => Reprocess());
  }
  catch (Exception ex)
  {
    Msg.Add(new clsMSG(ex.Message, "Error", DateTime.Now));
    timer.Stop();
    stopWatch.Stop();
    throw;
  }
}

如果 Reprocess 抛出异常,该异常将被放置在从 Task.Run 返回的任务中。当您的代码 await 执行该任务时,该异常会重新引发并在 catch 中捕获。在 catch 结束时,代码将重新引发该异常 (throw;)。