-2

一些伪代码来说明我的问题:

public async Task DoSomethingAsync()
{
   try
   {
      var task1 = DoThisAsync(); // throws exception
      var task2 = DoThatAsync();

      await task1.Then(t => Handle(t));
      await task2.Then(t => Handle(t));
   }
   catch (AggregateException)
   {
      Console.WriteLine("Whatnow?");
   }
}

然后定义如下:

// from https://gist.github.com/rizal-almashoor/2818038
public static Task Then(this Task task, Action<Task> next)
{ 
   var tcs = new TaskCompletionSource<AsyncVoid>();

   task.ContinueWith(t=>
   {
      if (t.IsFaulted)
         tcs.TrySetException(t.Exception); // continuing task1 this line only gets hit
                                           // after DoThatAsync() is completed??
      else
      {
         try
         {
            next(t);
            tcs.TrySetResult(default(AsyncVoid));
         }
         catch (Exception ex)
         {
            tcs.TrySetException(ex);
         }
      }
   });

   return tcs.Task;
}

所以我的问题是,出于某种原因,即使 DoThisAsync() 很早就抛出了异常,但在 DoThatAsync() 完成之前我看不到“whatnow”。这不是确切的代码,我试图简化以免浪费您的时间。如果这里没有任何东西可以解释这种行为,请告诉我,我会添加更多细节。

编辑

出于这个问题的目的,我们可以想象 DoThisAsync() 和 DoThatAsync() 是异步方法,基本上执行以下操作:

DoThisAsync:
   Thread.Sleep(30000);    // wait a short perioud of time
   throw new Exception();  // and throw an exception

DoThatAsnyc:
   Thread.Sleep(240000);   // wait a long period of time
4

1 回答 1

1

大概您DoThisAsync开始了一项新任务,并且该任务的动作是引发异常的原因-对吗?

在这种情况下,异常存储在任务中。除非您调用像 .Wait 或 .Result 这样的触发器方法,否则不会重新引发异常。当您await从 中返回任务时Then,它会导致该任务的异常被重新抛出。

编辑: 根据您的编辑显示 DoThisAsync:当async返回 Task 的标记方法导致异常时,该异常存储在 Task 中(而不是允许它传播)。如果您要删除async关键字,我希望在调用 DoThisAsync 时发生异常。

编辑: 来自 Stephen Toub 的 Async/Await 常见问题解答: http: //blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx

当应用于方法时,“async”关键字有什么作用?

当您使用“async”关键字标记方法时,您实际上是在告诉编译器两件事:

  1. 您告诉编译器您希望能够在方法中使用“await”关键字(当且仅当它所在的方法或 lambda 标记为异步时,您才能使用 await 关键字)。这样做时,您是在告诉编译器使用状态机编译该方法,以便该方法能够挂起,然后在等待点异步恢复。
  2. 您是在告诉编译器“提升”方法的结果或返回类型中可能出现的任何异常。对于返回 Task 或 Task 的方法,这意味着在方法中未处理的任何返回值或异常都将存储到结果任务中。对于返回 void 的方法,这意味着任何异常都会通过方法初始调用时当前的任何“SynchronizationContext”传播到调用者的上下文。
于 2013-03-06T14:28:05.177 回答