Task <int>はどのようにしてintになりますか?


116

この方法があります:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

   Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

   // You can do work here that doesn't rely on the string from GetStringAsync.
   DoIndependentWork();

   string urlContents = await getStringTask;
   //The thing is that this returns an int to a method that has a return type of Task<int>
   return urlContents.Length;
}

Task<int>との間で暗黙的な変換が行われintますか?そうでない場合、何が起こっていますか?それはどのように機能するように実装されていますか?


1
読み続けてください。コンパイラはasyncキーワードに基づいてそれを処理すると思います。
Dスタンリー

1
@Freeman、この素晴らしい説明を見てください:stackoverflow.com/a/4047607/280758
qehgt

回答:


171

Task <>とintの間で暗黙的な変換が発生しますか?

いいえ。これはasync/のawait動作の一部にすぎません。

として宣言されたメソッドasyncには、次の戻り型が必要です。

  • void (可能であれば避けてください)
  • Task (完了/失敗の通知以外の結果はありません)
  • Task<T>T非同期のタイプの論理結果の場合)

コンパイラーはすべての適切なラッピングを行います。重要なのは、非同期に戻るということです。実際のメソッドは、まだ完了していない最初の式にヒットしたときにurlContents.Length戻るため、メソッドを単にに戻すことはできません。したがって、代わりに、非同期メソッド自体が完了すると完了するa を返します。intawaitTask<int>

await反対をする-それはアンラップTask<T>Tこのラインがどのように働くかの値:

string urlContents = await getStringTask;

...しかし、もちろんそれは非同期にアンラップしますが、使用Resultするだけではタスクが完了するまでブロックされます。(awaitawaitableパターンを実装する他のタイプをアンラップできTask<T>ますが、これは最も頻繁に使用するものです。)

この二重のラッピング/アンラッピングにより、非同期を非常に構成可能にすることができます。たとえば、私はあなたのものを呼び出して結果を倍にする別の非同期メソッドを書くことができます:

public async Task<int> AccessTheWebAndDoubleAsync()
{
    var task = AccessTheWebAsync();
    int result = await task;
    return result * 2;
}

(または単にreturn await AccessTheWebAsync() * 2;もちろん。)


3
内部でどのように機能するかについての詳細を提供できますか?
フリーマン、

8
+1いつものように良い答え。そして、なぜあなたはそれらをとても速く書くのですか?
Felix K.

9
+1:ちょうどasync/ awaitを調べ始めたところ、これは非常に直感的ではないことがわかりました。IMO、returnこれを明確にするために、たとえばにキーワードまたは同様のものが必要ですreturn async result;(からをawait result「アンラップ」するのと同じ方法で)。TTast<T>
dav_i

2
@JonSkeetしかし、それなしでは意味がありませんawait- T foo = someTaskT;あなたは「暗黙的に型Task<T>をに変換できません」を得るでしょうT-同じ方法で、逆のキーワードを持つことはより意味があると主張します(でラップするTask<T>)。私は綿毛を取り除くためにすべてですが、この場合、それはasyncメソッド内で不必要な難読化を提供すると思います。(明らかに、すでに話されている/コード化されているパワーがあるため、要点は議論の余地があります!)
dav_i

2
@dav_i:割り当ては意味がありませんが、残りは意味があります。そして、ステートメント全体が意味をなす場合があります-それは役に立たないかもしれませんが。メソッドがすでに宣言されているasyncことを考えると、それで十分だと思います。
Jon Skeet 2013年

18

タスクをintに変換する必要はありません。単にタスク結果を使用します。

int taskResult = AccessTheWebAndDouble().Result;

public async Task<int> AccessTheWebAndDouble()
{
    int task = AccessTheWeb();
    return task;
}

可能な場合は値を返し、それ以外の場合は0を返します。


20
それは私が尋ねたものではありません。
Freeman

16
これは質問の答えにはなりません。しかし、もっと重要なことに、これは非常に悪いアドバイスです。ほとんど使用しないでくださいResult。デッドロックを引き起こす可能性があります。たとえば、次のワークフローについて考えてみます。(1)「芝生を刈る」というメモを書きます。(2)芝生が刈られるまで待ちます(3)サンドイッチを食べます、(4)ノートに書かれていることを何でも行います。 "このワークフローでは、ステップ2は同期待機であるため、サンドイッチを食べたり芝生を刈ったりすることはありません。将来行うことについて何かを説明しますが、ここで説明するのはワークフローです
Eric Lippert

@EricLippert:例を明確にしないでください。待つことができないときにResultがデッドロックをどのように導入できるか説明していただけますか?
CharithJ

3
待機とは、結果を待っている間に何かを行うことを意味し、その結果には、結果を計算するための作業を含めることができます。しかし、同期待機は、待機している間は何もしません。つまり、作業の実行を妨げている可能性があります。
Eric Lippert

1
@EricLippert。これには同じ問題がありますか?'Task.Run(()=> AccessTheWebAndDouble())。Result;'
CharithJ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.