Bagaimana Task <int> menjadi int?

116

Kami memiliki metode ini:

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;
}

Apakah konversi implisit terjadi antara Task<int>dan int? Jika tidak, lalu apa yang terjadi? Bagaimana penerapannya untuk bekerja?

Warga kehormatan
sumber
1
Teruskan membaca . Saya berasumsi bahwa kompilator mengurusnya berdasarkan asynckata kunci.
D Stanley
1
@ Freeman, Lihatlah penjelasan hebat ini: stackoverflow.com/a/4047607/280758
qehgt

Jawaban:

171

Apakah konversi implisit terjadi antara Tugas <> dan int?

Nggak. Ini hanyalah bagian dari cara async/ awaitbekerja.

Metode apa pun yang dideklarasikan asyncharus memiliki tipe kembalian:

  • void (hindari jika memungkinkan)
  • Task (tidak ada hasil selain pemberitahuan penyelesaian / kegagalan)
  • Task<T>(untuk hasil logis dari tipe Tdengan cara async)

Kompilator melakukan semua pembungkusan yang sesuai. Intinya adalah Anda kembali secara asinkronurlContents.Length - Anda tidak dapat membuat metode hanya kembali int, karena metode sebenarnya akan kembali ketika mencapai awaitekspresi pertama yang belum selesai. Jadi, ia mengembalikan nilai Task<int>yang akan selesai ketika metode asinkron itu sendiri selesai.

Perhatikan bahwa awaittidak sebaliknya - itu unwraps sebuah Task<T>ke Tnilai, yang adalah bagaimana baris ini bekerja:

string urlContents = await getStringTask;

... tapi tentu saja itu membuka bungkusnya secara tidak sinkron, sedangkan hanya menggunakan Resultakan memblokir sampai tugas selesai. ( awaitdapat membuka jenis lain yang menerapkan pola yang dapat menunggu, tetapi yang Task<T>paling sering Anda gunakan.)

Pembungkusan / pembungkusan ganda inilah yang memungkinkan asinkron menjadi begitu mudah disusun. Misalnya, saya bisa menulis metode asinkron lain yang memanggil Anda dan menggandakan hasilnya:

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

(Atau return await AccessTheWebAsync() * 2;tentu saja.)

Jon Skeet
sumber
3
dapat detail apa pun ditawarkan untuk cara kerjanya di bawah tenda, hanya ingin tahu.
Freeman
8
+1 Jawaban bagus seperti biasa. Dan kenapa kamu begitu cepat menulisnya ?!
Felix K.
9
+1: Baru saja mulai mencari async/ awaitdan menurut saya ini sangat tidak intuitif. IMO, harus ada kata kunci atau serupa di returnuntuk membuatnya jelas, misalnya return async result;(dengan cara yang sama yang await result"membuka" Tdari Tast<T>).
dav_i
2
@JonSkeet Tapi itu tidak masuk akal tanpa await- dengan T foo = someTaskT;Anda akan mendapatkan "Tidak bisa secara implisit mengubah tipe Task<T>menjadi T" - dengan cara yang sama saya berpendapat bahwa akan lebih masuk akal untuk memiliki kata kunci untuk invers (membungkus dalam Task<T>). Saya semua untuk menghilangkan bulu tetapi dalam kasus ini saya pikir itu memberikan kebingungan yang tidak perlu dalam asyncmetode. (Jelas intinya diperdebatkan karena kekuatan yang telah diucapkan / dikodekan!)
dav_i
2
@dav_i: Penugasan tidak masuk akal, tetapi sisanya masuk akal. Dan ada kasus di mana seluruh pernyataan akan masuk akal - meski mungkin tidak berguna. Mengingat metode ini sudah dideklarasikan async, saya rasa itu sudah cukup.
Jon Skeet
18

Tidak perlu mengubah Tugas menjadi int. Cukup Gunakan Hasil Tugas.

int taskResult = AccessTheWebAndDouble().Result;

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

Ini akan mengembalikan nilai jika tersedia jika tidak mengembalikan 0.

Aniket Sharma
sumber
20
bukan itu yang saya minta.
Freeman
16
Ini tidak menjawab pertanyaan itu. Tetapi yang lebih penting, ini adalah nasihat yang sangat buruk . Anda hampir tidak boleh menggunakan Result; itu bisa menyebabkan kebuntuan! Pertimbangkan misalnya alur kerja ini: (1) Tulis catatan yang mengatakan "potong rumput". (2) Menunggu rumput dipangkas (3) Makan sandwich, (4) Lakukan apa pun yang tertulis di catatan ". Dengan alur kerja itu, Anda tidak pernah makan sandwich atau memotong rumput, karena langkah 2 adalah menunggu yang sinkron tentang sesuatu yang akan Anda lakukan di masa depan . Tapi itulah alur kerja yang Anda gambarkan di sini.
Eric Lippert
@EricLippert: Tidak menghapus contoh Anda. Bisakah Anda menjelaskan bagaimana Result dapat menyebabkan kebuntuan ketika await tidak mau?
CharithJ
3
Await berarti melakukan sesuatu sambil menunggu hasilnya dan sesuatu dapat mencakup melakukan pekerjaan untuk menghitung hasilnya. Tetapi penantian sinkron tidak melakukan apa pun saat Anda menunggu yang berarti Anda dapat mencegah pekerjaan selesai.
Eric Lippert
1
@Bayu_joo Apakah ini memiliki masalah yang sama? 'Task.Run (() => AccessTheWebAndDouble ()). Hasil;'
CharithJ