在c#任务中不等待地重新抛出异常

本文关键字:抛出异常 等待 任务 | 更新日期: 2023-09-27 18:17:54

我有一个GUI应用程序,我想在任务中运行一些东西,所以它不会保留UI。我希望将任务中未处理的异常传播到应用程序级异常处理程序。然而:

    如果我只是在任务中抛出一个异常,它将不会达到应用程序级别除非我使用wait/await
  1. Async/Await -我从UI构造函数调用方法,所以我不能在那里使用Async/Await,因为我需要继续构造。我只想运行任务,然后忘记。

我正在考虑使用dispatcher。你觉得怎么样?

public MainWindow()
{
        InitializeComponent();
        MyMethodAsync();
        InitializeA();
        IntiializeB();
}
private void MyMethodAsync()
{
     Task t = Task.Run(() =>
     {
          //Do some stuff
          throw new Exception("Throwing some unexpected exception");
     }).ContinueWith(MyContinueWith);
}
private void MyContinueWith(Task task)
{
    if (task.IsFaulted && task.Exception != null)
    {
         dispatcher.BeginInvoke(new Action(() =>
         {
            throw task.Exception;
         }), null);
    }
}

在c#任务中不等待地重新抛出异常

我能想到两种方法。首先,注册到TaskScheduler.UnobservedTaskException事件并记录您需要的任何内容:

private void MyMethodAsync()
{
    // Note you should probably register only once, so this may not fit here.
    TaskScheduler.UnobservedTaskException += (s, e) => GlobalLogger.Log(e);
    Task t = Task.Run(() =>
    {
        // Do some staff
    }).ContinueWith(MyContinueWith);
}

由于某些原因你不想使用的更好的选择是,实际上等待操作并将其包装在try-catch中:

private async Task MyMethodAsync()
{
    try
    {
       await Task.Run(() =>
       {
          // Do some staff
       });
       InvokeContinuation();
    }
    catch (Exception e)
    {
        // Log.
    }
}

通过调用Task来实现这一点。运行时,通常会生成一个新线程,这在大多数情况下不太可能是你想要的。在某些情况下,创建新线程是有意义的,因为您需要执行CPU限制的工作,在这种情况下,您需要考虑利用其他并行计算库来最大限度地利用它。相反,如果您的工作是I/O绑定的,您应该能够一直使用异步调用。

为了等待一个异步方法调用的结果或一个异常冒泡到调用点,你总是可以在异步方法返回的任务上附加一个ContinueWith调用。如果你正在处理结果和任何可能的异常,那么async/await语义工作得很好。但是请注意,默认情况下,在这些延续中执行的代码可能不会在与原始线程相同的线程中执行。