2017-12-19 49 views
0

私のコードは、非同期メソッドと例外処理を組み合わせています。コードは非常に単純であり、すべてのタスクが待っていると何のasync void方法はありません:例外が飲み込まれたため、例外をスローしません、このメソッドを待ち非同期メソッドの例外処理が例外をキャッチしない驚くべきケース

async Task DoWorkSafelyWithStateMachine() 
{ 
    try 
    { 
     await DoWorkThatMightThrowException(); 
    } 
    catch (Exception exception) 
    { 
     Console.WriteLine("With state machine: " + exception.Message); 
    } 
} 

は:

await DoWorkSafelyWithStateMachine(); // No exception thrown 

しかし、コードはありません例外を常にキャッチするとは限りません。この方法は全く非同期ステートマシンは、コンパイラによって作成されていない少し異なる方法で書かれているときに問題が生じる:

Task DoWorkSafelyWithoutStateMachine() 
{ 
    try 
    { 
     return DoWorkThatMightThrowException(); 
    } 
    catch (Exception exception) 
    { 
     Console.WriteLine("Without state machine: " + exception.Message); 
     return Task.CompletedTask; 
    } 
} 

方法をasyncで飾られていないと何もメソッド内待望されていません。代わりに、try内のメソッドによって返されたタスクが呼び出し側に返されます。しかし、私の経験では、コンパイラの魔法はどういうわけか、まだtryのメソッドが例外をスローすると、例外ハンドラによって捕捉されることを保証します。まあ、明らかにそれは常に真実ではありません。

同じメソッドのこれらの2つのバリエーションをテストするには、私はDoWorkThatMightThrowException例外をスローします。この方法は、メソッドの本体でawaitを使用する必要がない場合、それがまたは非同期ステートマシンもしなくても実装できます。

async Task DoWorkThatMightThrowExceptionWithStateMachine() 
{ 
    throw new Exception("With state machine"); 
    await Task.CompletedTask; 
} 

Task DoWorkThatMightThrowExceptionWithoutStateMachine() 
{ 
    throw new Exception("Without state machine"); 
    return Task.CompletedTask; 
} 

DoWorkSafelyWithoutStateMachineからDoWorkThatMightThrowExceptionWithStateMachineを呼び出すと例外がスローされたキャッチしていないことを私が発見しました。他の3つの組み合わせは例外をキャッチします。特に、どちらのメソッドにも非同期状態マシンが含まれていないバージョンでは例外が発生しますが、誤ってこのコードを外挿すると、コードの一部に微妙なエラーが発生するという不幸な結果になります。

 
          | Throw + state machine | Throw - state machine | 
--------------------------+-----------------------+-----------------------+ 
Try/catch + state machine |  Caught   |  Caught   | 
Try/catch - state machine |  Not caught  |  Caught   | 

私は、私はいつもawaittryブロック(テーブルの最初の行)内のタスクを持っていることを学びました。この実験を行います。しかし、私はテーブルの2番目の行の不一致を理解していません。この現象を説明してください。それはどこに文書化されていますか?これに関する情報を検索することは容易ではありません。タスクが待たれていないために例外が「失われている」という基本的な問題は、検索結果を支配します。

+0

質問はしていません。 – Servy

+1

@セイビー:私は黙示的な質問に理解できないと思った。しかし、私はフレーズを少し修正し、さらに疑問符を追加しました。 –

+0

上記の方法とそれらがどのように実行されるのかを[MCVE]に見ていただければ幸いです。あなたのコードは...奇妙なようです。あなたは*タスク内でスローされた例外をどのように管理するのかを誤解しているかもしれません。すべての作品をまとめることなく伝えるのは難しい。 – Will

答えて

3

私はテーブル

右サイドケース(まったくステート・マシン)の2行目の矛盾を理解していないが簡単です:

  • あなたがメソッドを呼び出します内部try/catchブロック
  • このメソッドは例外をスローします
  • catch黒はそれをキャッチします - 何も特別な

左側には、あまりにも、理解することは実際には簡単です:

  • あなたは
  • try/catchブロック内でメソッドを呼び出しますが、この方法は、それが状態に変換されている、それが思われるものではありません 機械、だから何それは返すことは、あなたがそれを実装としてWaitので、限り、あなたがそうであるように(1)
  • 方法のコンテンツの実行を表していないか、TaskですawaitTaskを返したか、そのResultプロパティにアクセスしようとしましたが、例外はあなたのtryブロック内に(再)スローされません。

(1)私は英語がより良く、より正確な記述を見つけることが優れていた希望。 Servyが指摘したように、あなたの例では、既にフォールトされたTaskが返されます。

3

ブロックに例外がスローされたときにブロックが実行されます。 return DoWorkThatMightThrowExceptionWithStateMachine();を書き込むと、tryブロックが実行している間に、Taskがfaultedとマークされて返されます。例外は一度もスローされないので、catchブロックは実行されません。

エラーが発生したタスクを待っている場合は、その例外がスローされ、例外がスローされます。 DoWorkThatMightThrowExceptionWithoutStateMachineを呼び出すと、メソッド自体が例外をスローして、エラーの発生したタスクを返さないため、tryブロックに例外がスローされます。

関連する問題