さまざまなC#非同期CTPサンプルを見ると、void
を返す非同期関数と、非ジェネリックTask
を返す非同期関数がいくつかあります。非同期操作が完了したときに呼び出し元にデータを返すのにTask<MyType>
を返すことが便利な理由はわかりますが、Task
の戻り型を持つ関数はデータをまったく返しません。なぜvoid
を返さないのですか?
SLaksとKillercamの答えは良いです。コンテキストをもう少し追加すると思いました。
最初の質問は、本質的にasync
とマークできるメソッドについてです。
async
としてマークされたメソッドは、void
、Task
、または_Task<T>
_を返すことができます。それらの違いは何ですか?
非同期メソッドを返す_Task<T>
_を待つことができ、タスクが完了するとTが付与されます。
非同期メソッドを返すTask
を待つことができ、タスクが完了すると、タスクの継続が実行されるようにスケジュールされます。
非同期メソッドを返すvoid
を待つことはできません。それは「火と忘れ」の方法です。非同期で動作し、いつ終了したかを知る方法はありません。これは少し奇妙です。 SLaksが言うように、通常は非同期イベントハンドラーを作成するときにのみそうします。イベントが発生すると、ハンドラーが実行されます。イベントハンドラーはタスクを返さないため、イベントハンドラーから返されたタスクを誰も「待機」することはありません。通常、最初にハンドラーに制御を移すのはユーザーコードではありません。
コメントの2番目の質問は、基本的にawait
edにできることに関するものです。
どのような種類のメソッドを
await
edできますか? voidを返すメソッドをawait
edにできますか?
いいえ、ボイドを返すメソッドは待ち切れません。コンパイラはawait M()
をM().GetAwaiter()
の呼び出しに変換します。ここで、GetAwaiter
はインスタンスメソッドまたは拡張メソッドです。待機値は、待機者を取得できる値である必要があります。明らかに、voidを返すメソッドは、待機者を取得できる値を生成しません。
Task
- returningメソッドは、待機可能な値を生成できます。サードパーティは、待つことができるTask
のようなオブジェクトの独自の実装を作成することを望んでおり、あなたはそれらを待つことができるでしょう。ただし、async
、void
、または_Task<T>
_以外を返すTask
メソッドを宣言することはできません。
(更新:C#の将来のバージョンによって改ざんされる可能性がある私の最後の文。非同期メソッドのタスクタイプ以外の戻りタイプを許可する提案があります。)
(更新:上記の機能により、C#7になりました。)
呼び出し元がタスクを待つか、継続を追加する場合。
実際、void
を返す唯一の理由は、イベントハンドラを記述しているためにcannot return Task
である場合です。
Task
およびTask<T>
を返すメソッドは構成可能です。つまり、await
メソッド内でasync
を使用できます。
async
を返すvoid
メソッドは構成できませんが、他にも2つの重要なプロパティがあります。
2番目のポイントは、未処理の非同期操作のcountを維持するコンテキストを扱う場合に重要です。
ASP.NETコンテキストはそのようなコンテキストの1つです。非同期Task
メソッドから待たずに非同期void
メソッドを使用すると、ASP.NET要求が早く完了します。
別のコンテキストは、ユニットテスト用に書いたAsyncContext
です(利用可能 ここ )-AsyncContext.Run
メソッドは、未処理の操作カウントを追跡し、ゼロのときに戻ります。
タイプTask<T>
はタスク並列ライブラリ(TPL)の主力タイプで、「将来的にタイプT
の結果を生成する作業/ジョブ」の概念を表します。 「将来は完了するが結果を返さない作業」という概念は、非汎用タスクタイプによって表されます。
タイプT
の結果がどのように生成されるかは、特定のタスクの実装の詳細です。 TPLタスクは通常、現在のプロセスのスレッドプールからワーカースレッドにファームアウトされますが、その実装の詳細はTask<T>
タイプの基本ではありません。むしろ、Task<T>
は、T
を生成する高遅延操作を表すことができます。
上記のコメントに基づいて:
await
式は、「この式を評価して、将来結果を生成する作業を表すオブジェクトを取得します。現在のメソッドの残りを、そのタスクの継続に関連付けられたコールバックとしてサインアップします。が生成され、コールバックがサインアップされ、即時に呼び出し元に制御が戻ります」。これは通常のメソッド呼び出しとは対照的/対照的です。つまり、「何をしているのかを記憶し、このメソッドを完全に終了するまで実行し、その後メソッドの結果を知って中断したところから始めます」。
編集:2011年10月のMSDNマガジンのEric Lippertの記事を引用する必要があります。最初にこのことを理解する上で大きな助けになったからです。
より多くの情報とホワイトページの読み込みについては、 here を参照してください。
これが助けになることを願っています。