-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。タスクを返すマークされたメソッドが例外を発生させた場合、その例外は(伝播を許可するのではなく)タスクに格納されます。キーワードを削除するasyncと、DoThisAsyncが呼び出されたときに例外が発生することが予想されます。

編集: StephenToubのAsync/ Await FAQから: http: //blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx

メソッドに適用された場合、「async」キーワードは何をしますか?

「async」キーワードでメソッドをマークすると、実際にはコンパイラーに2つのことを伝えていることになります。

  1. メソッド内で「await」キーワードを使用できるようにすることをコンパイラーに指示しています(メソッドまたはラムダが非同期としてマークされている場合にのみ、awaitキーワードを使用できます)。そうすることで、ステートマシンを使用してメソッドをコンパイルするようにコンパイラーに指示します。これにより、メソッドは待機ポイントで非同期に一時停止してから再開できるようになります。
  2. メソッドの結果または発生する可能性のある例外を戻り型に「リフト」するようにコンパイラーに指示しています。TaskまたはTaskを返すメソッドの場合、これは、メソッド内で処理されない戻り値または例外が結果タスクに格納されることを意味します。voidを返すメソッドの場合、これは、メソッドの最初の呼び出し時に現在の「SynchronizationContext」を介して、すべての例外が呼び出し元のコンテキストに伝播されることを意味します。
于 2013-03-06T14:28:05.177 に答える