2016-06-14 7 views
1

C#で非同期待機を使用する場合、誰かが戻り値の型を整理できることを期待しています。タスク< T>、タスクと無効の3つの戻り値の型があることを理解しています。これについて学ぶことから、特殊な状況(イベントハンドラ)でのみvoidを使用し、同期メソッドを非同期メソッドに変更する場合はvoidキーワードをTaskに変更する必要があります。C#.NET非同期返される型を返します

私の質問は、コードが完全に独立しており、結果が継続のために重要ではないのに、タスクの戻り値の型が必要ですか?たとえば、非同期メソッドを使用していくつかの情報をWebサービスにプッシュするとします。

私が説明するために、小さな例を作成しました:

private void CallingMethod() 
    { 
     AsyncMethod(); 
     AsyncTaskMethod(); // any difference between doing these? (not exc handling) 

     var task = AsyncTaskMethod(); // should I do anything with this task 
             // before I continue? Or is it simply 
             // just to show the user that it's async?? 


     // continue with unrelated code that doesnt require task or any code from above 
    } 

    private async void AsyncMethod() // is void okay? 
    { 
     await LongRunningMethod(); 

     // do other stuff 
    } 

    private async Task AsyncTaskMethod() // or should it be Task? 
    { 
     await LongRunningMethod(); 

     // do other stuff 
    } 

    private async Task LongRunningMethod() 
    { 
     // do long running code 
    } 

私のアプリケーションは、そのようなメソッドをたくさん持っている:

private void BigMethod() 
    { 
     DoStuff(); 

     DoMoreStuff(); 

     AsyncMethod(); // is this right? Or should I have the task declaration too? 

     UnrelatedStuff(); 
    } 

    private async Task AsyncMethod() // should this return task? 
    { 
     var result = await GetUserId(); 

     if (result == null) 
      return; 

     MyUserId = result; 
    } 

    private async Task<int> GetUserId() 
    { 
     // do long running code 
     return 1; 
    } 

それはすべての手段によって、はっきりしていない場合は、単に言うと、Iそれをちょっと整理しよう。みんなありがとう。

EDIT:CallingMethod上記使用していない最初のコメントに応答して

private void CallingMethod() 
    { 
     AsyncMethod(); 
    } 

    private async void AsyncMethod() 
    { 
     await LongRunningMethod(); 
    } 

    private async Task LongRunningMethod() 
    { 
     await Task.Run(() => 
     { 
      Thread.Sleep(4000); 
     }); 

     MessageBox.Show("Done!"); 
    } 

は/非同期待って、それは喜んで、メッセージボックスをポップアップ、GUIスレッドをロックせずに4秒間スリープ。どうしたの?

+1

CallingMethod()は 'async'と' await'を使うべきです。それがなければ質問はほとんど意味がない。 –

+0

"async"は "parellel"と同じではないことに注意してください。 "await"行の後のコードは、その行が待たれるまで実行されません。 –

+0

これは必要ありませんか?編集を確認してください – Murphybro2

答えて

1

voidを返すメソッドを待つことができず、主な理由の1つは、voidを返す非同期メソッドの呼び出し元がasyncメソッドからスローされた例外をキャッチできないことです。それを試してみてください:

public void TryToCatchMethod() { 
    try { 
     MyAsyncMethod(); 
    } catch (Exception exception) { 
     //tha catch is never called 
     Debug.WriteLine(exception.ToString()); 
    } 
    } 
    public async void MyAsyncMethod() { 
    throw new Exception(); 
    } 
+0

大丈夫、ありがとう、thats素晴らしい。だから、代替手段は何ですか? voidをTaskに置き換えますか?そうすることで、例外がプログラムをクラッシュさせるのを止めますが、どちらかとらえられないようですか? – Murphybro2

+0

これを次のように置き換えます。public async Task MyAsyncMethod(){ throw new Exception(); }それを待っていると、catchブロックがどのように実行されるかがわかります。 –

3

あなたはメソッドがvoidを返すとき使用Taskする必要はありませんが、それは確かにいくつかの理由から、好ましい:Taskを返す

  1. 非同期メソッド(またはTask<T>)は、返されたTaskに例外を設定しています。したがって、呼び出しメソッドは、Taskにフォルトが発生しているかどうかをチェックできます。

  2. Async void方法は、その例外はほとんどそれを作る、呼び出し元の同期コンテキストに直接投げられている(あなたはまだグローバル例外ハンドラを使用することができますので、ほぼが、それは大きなアプリケーションのためにunmaintainableです)決定論的にそれらの例外を処理することは不可能方法。

  3. あなたは、基本的には、発信者によって実行されたときに

  4. async void方法が完全であると想定される例外をスローする可能性のあるasync voidメソッドをテストすることはできません。実際には、既存のライブラリを非同期に変換しようとすると、イベントハンドラに多くの問題があります。まずは、比較的複雑なサードパーティ製のwinformsライブラリを取得し、イベントハンドラを非同期化しようとすると、それが作成する大混乱を参照してください!)。

  5. ありasync voidメソッドが終了したときに決定するための合理的な方法ではありません(あなたがあなた自身のSynchronizationContextを作ることができるが、それは間違いなく、複雑な何か)あなたがすることはできません(async voidコールを設定することはできません

  6. それにはConfigureAwaitを使用します)、継続コンテキストは常に呼び出し側の同期コンテキストです。

そう...

TL; DR:(つまり:void署名を期待するイベントハンドラで)あなたはそれを避けることができない場合を除きasync voidを使用しないでください。それには理由があります。結果が期待されない場合は、async Taskを使用してください。

+0

わかりましたので、私はこのコードを持っている: ます。public void TryToCatchMethodを(){ は { MyAsyncMethodを()してみてください。 } catch(例外例外) { // tha catchは呼び出されません Debug.WriteLine(exception.ToString()); } } パブリックasync void MyAsyncMethod() { throw new Exception(); } 例外がスローされると、アプリケーションがクラッシュし、処理されない例外が発生します。だから私は例外をキャプチャするためにそれを変更するだろうか? – Murphybro2

+0

フォーマットをお詫び申し上げます。フォーマットされたバージョンのRadin Gospodinovsの回答 – Murphybro2

+0

非同期メソッドが 'Task'を返すようにして、呼び出しメソッドがそれを' await'するようにしてください:[ここで確認してください](https://dotnetfiddle.net/zU93YA )。 *非同期にしてください(そして、私たちがいる間、呼び出し元のメソッドも 'Task'を返すように変更してください) – Jcl

関連する問題