Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Metode asinkron dapat memiliki jenis pengembalian berikut:
- Task, untuk metode asinkron yang melakukan operasi tetapi tidak mengembalikan nilai.
- Task<TResult>, untuk metode asinkron yang mengembalikan nilai.
-
void, untuk penanganan aktivitas. - Jenis apa pun yang memiliki metode
GetAwaiteryang dapat diakses. Objek yang dikembalikan oleh metodeGetAwaiterharus mengimplementasikan antarmuka System.Runtime.CompilerServices.ICriticalNotifyCompletion. - IAsyncEnumerable<T>, untuk metode asinkron yang mengembalikan aliran asinkron .
Untuk informasi selengkapnya tentang metode asinkron, lihat Pemrograman asinkron dengan async dan await (C#).
Beberapa jenis lain juga ada yang khusus untuk beban kerja Windows:
- DispatcherOperation, untuk operasi asinkron terbatas pada Windows.
- IAsyncAction, untuk tindakan asinkron di aplikasi Universal Windows Platform (UWP) yang tidak mengembalikan nilai.
- IAsyncActionWithProgress<TProgress>, untuk tindakan asinkron di aplikasi UWP yang melaporkan kemajuan tetapi tidak mengembalikan nilai.
- IAsyncOperation<TResult>, untuk operasi asinkron di aplikasi UWP yang mengembalikan nilai.
- IAsyncOperationWithProgress<TResult,TProgress>, untuk operasi asinkron di aplikasi UWP yang melaporkan kemajuan dan mengembalikan nilai.
Jenis pengembalian tugas
Metode asinkron yang tidak berisi pernyataan return atau yang berisi pernyataan return yang tidak mengembalikan operand biasanya memiliki jenis pengembalian Task. Metode tersebut mengembalikan void jika berjalan secara sinkron. Jika Anda menggunakan jenis pengembalian Task untuk metode asinkron, metode yang memanggil dapat menggunakan operator await untuk menangguhkan proses penyelesaian dari pemanggil sampai metode asinkron yang disebut selesai.
Dalam contoh berikut, metode WaitAndApologizeAsync tidak berisi pernyataan return, sehingga metode mengembalikan objek Task. Mengembalikan Task memungkinkan WaitAndApologizeAsync ditunggu. Jenis Task tidak menyertakan properti Result karena tidak memiliki nilai pengembalian.
public static async Task DisplayCurrentInfoAsync()
{
await WaitAndApologizeAsync();
Console.WriteLine($"Today is {DateTime.Now:D}");
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Console.WriteLine("The current temperature is 76 degrees.");
}
static async Task WaitAndApologizeAsync()
{
await Task.Delay(2000);
Console.WriteLine("Sorry for the delay...\n");
}
// Example output:
// Sorry for the delay...
//
// Today is Monday, August 17, 2020
// The current time is 12:59:24.2183304
// The current temperature is 76 degrees.
WaitAndApologizeAsync ditunggu dengan menggunakan pernyataan tunggu alih-alih ekspresi tunggu, mirip dengan pernyataan panggilan untuk metode pengembalian kekosongan sinkron. Penggunaan operator tunggu dalam hal ini tidak menghasilkan nilai. Ketika operand kanan await adalah Task<TResult>, ekspresi await menghasilkan hasil T. Ketika operan kanan dari await adalah Task, maka await dan operannya adalah sebuah pernyataan.
Anda dapat memisahkan panggilan ke WaitAndApologizeAsync dari aplikasi operator tunggu, seperti yang ditunjukkan oleh kode berikut. Namun, ingatlah bahwa Task tidak memiliki properti Result, dan tidak ada nilai yang dihasilkan ketika operator await dikenakan pada Task.
Kode berikut memisahkan pemanggilan metode WaitAndApologizeAsync dari menanti tugas (task) yang dikembalikan oleh metode tersebut.
Task waitAndApologizeTask = WaitAndApologizeAsync();
string output =
$"Today is {DateTime.Now:D}\n" +
$"The current time is {DateTime.Now.TimeOfDay:t}\n" +
"The current temperature is 76 degrees.\n";
await waitAndApologizeTask;
Console.WriteLine(output);
Jenis pengembalian tugas<TResult>
Jenis pengembalian Task<TResult> digunakan untuk metode asinkron yang berisi pernyataan pengembalian dengan operand TResult.
Dalam contoh berikut, metode GetLeisureHoursAsync berisi pernyataan return yang mengembalikan bilangan bulat. Deklarasi metode harus menentukan jenis pengembalian Task<int>. Metode asinkron FromResult adalah sebuah placeholder untuk operasi yang mengembalikan DayOfWeek.
public static async Task ShowTodaysInfoAsync()
{
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await GetLeisureHoursAsync()}";
Console.WriteLine(message);
}
static async Task<int> GetLeisureHoursAsync()
{
DayOfWeek today = await Task.FromResult(DateTime.Now.DayOfWeek);
int leisureHours =
today is DayOfWeek.Saturday || today is DayOfWeek.Sunday
? 16 : 5;
return leisureHours;
}
// Example output:
// Today is Wednesday, May 24, 2017
// Today's hours of leisure: 5
Ketika GetLeisureHoursAsync dipanggil dari dalam ekspresi tunggu dalam metode ShowTodaysInfo, ekspresi tunggu mengambil nilai bilangan bulat (nilai leisureHours) yang disimpan dalam tugas yang dikembalikan oleh metode GetLeisureHours. Untuk informasi selengkapnya tentang menunggu ekspresi, lihat menunggu.
Anda dapat lebih memahami bagaimana await mengambil hasil dari Task<T> dengan memisahkan panggilan ke GetLeisureHoursAsync dari aplikasi await, seperti yang ditunjukkan kode berikut. Panggilan ke metode GetLeisureHoursAsync yang tidak segera ditunggu mengembalikan Task<int>, seperti yang Anda harapkan berdasarkan deklarasi metode. Tugas ditetapkan ke variabel getLeisureHoursTask dalam contoh. Karena getLeisureHoursTask adalah Task<TResult>, maka ia memiliki properti Result dengan tipe TResult. Dalam hal ini, TResult mewakili jenis bilangan bulat. Ketika await diterapkan ke getLeisureHoursTask, ekspresi tunggu akan menghasilkan nilai dari properti Result dari getLeisureHoursTask. Nilai ditetapkan ke variabel ret.
Penting
Properti Result adalah properti pemblokiran. Jika Anda mencoba mengaksesnya sebelum tugas tersebut selesai, utas yang saat ini aktif akan diblokir sampai tugas tersebut selesai dan nilainya tersedia. Dalam kebanyakan kasus, Anda harus mengakses nilai dengan menggunakan await alih-alih mengakses properti secara langsung.
Contoh sebelumnya mengambil nilai properti Result untuk memblokir utas utama sehingga metode Main dapat mencetak message ke konsol sebelum aplikasi berakhir.
var getLeisureHoursTask = GetLeisureHoursAsync();
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await getLeisureHoursTask}";
Console.WriteLine(message);
Jenis pengembalian void
Anda menggunakan jenis pengembalian void dalam penanganan aktivitas asinkron, yang memerlukan jenis pengembalian void. Untuk metode selain penanganan aktivitas yang tidak mengembalikan nilai, Anda harus mengembalikan Task sebagai gantinya, karena metode asinkron yang mengembalikan void tidak dapat ditunggu. Setiap pemanggil metode tersebut harus terus berjalan sampai selesai tanpa menunggu metode asinkron yang dipanggil selesai. Pemanggil harus independen dari nilai atau pengecualian apa pun yang dihasilkan metode asinkron.
Pemanggil metode asinkron yang mengembalikan nilai void tidak dapat menangkap pengecualian yang dilemparkan oleh metode tersebut. Pengecualian yang tidak tertangani tersebut kemungkinan menyebabkan aplikasi Anda gagal. Jika metode yang mengembalikan Task atau Task<TResult> melemparkan pengecualian, pengecualian disimpan dalam tugas yang dikembalikan. Pengecualian dilemparkan kembali ketika tugas ditunggu. Pastikan bahwa metode asinkron apa pun yang dapat menghasilkan pengecualian memiliki tipe pengembalian Task atau Task<TResult> dan bahwa panggilan ke metode tersebut harus menggunakan "await".
Contoh berikut menunjukkan perilaku penanganan aktivitas asinkron. Dalam kode contoh, penanganan aktivitas asinkron harus memberi tahu utas utama ketika selesai. Kemudian utas utama dapat menunggu penanganan aktivitas asinkron selesai sebelum keluar dari program.
public class NaiveButton
{
public event EventHandler? Clicked;
public void Click()
{
Console.WriteLine("Somebody has clicked a button. Let's raise the event...");
Clicked?.Invoke(this, EventArgs.Empty);
Console.WriteLine("All listeners are notified.");
}
}
public class AsyncVoidExample
{
static readonly TaskCompletionSource<bool> s_tcs = new TaskCompletionSource<bool>();
public static async Task MultipleEventHandlersAsync()
{
Task<bool> secondHandlerFinished = s_tcs.Task;
var button = new NaiveButton();
button.Clicked += OnButtonClicked1;
button.Clicked += OnButtonClicked2Async;
button.Clicked += OnButtonClicked3;
Console.WriteLine("Before button.Click() is called...");
button.Click();
Console.WriteLine("After button.Click() is called...");
await secondHandlerFinished;
}
private static void OnButtonClicked1(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 1 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 1 is done.");
}
private static async void OnButtonClicked2Async(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 2 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 2 is about to go async...");
await Task.Delay(500);
Console.WriteLine(" Handler 2 is done.");
s_tcs.SetResult(true);
}
private static void OnButtonClicked3(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 3 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 3 is done.");
}
}
// Example output:
//
// Before button.Click() is called...
// Somebody has clicked a button. Let's raise the event...
// Handler 1 is starting...
// Handler 1 is done.
// Handler 2 is starting...
// Handler 2 is about to go async...
// Handler 3 is starting...
// Handler 3 is done.
// All listeners are notified.
// After button.Click() is called...
// Handler 2 is done.
Jenis pengembalian asinkron umum dan< ValueTask>TResult
Metode asinkron dapat mengembalikan jenis apa pun yang memiliki metode GetAwaiter yang dapat diakses yang mengembalikan instans jenis awaiter. Selain itu, jenis yang dikembalikan harus cocok dengan jenis parameter dari SetResult dan jenis yang dikembalikan dari properti Task pada jenis yang ditentukan oleh atribut System.Runtime.CompilerServices.AsyncMethodBuilderAttribute. Anda dapat mempelajari lebih lanjut dalam artikel tentang atribut yang dibaca oleh pengkompilasi atau spesifikasi C# untuk pola pembangun tipe Task .
Fitur ini adalah pelengkap untuk ekspresi yang dapat ditunggu, yang menjelaskan persyaratan untuk operan await. Jenis pengembalian asinkron umum memungkinkan pengkompilasi untuk menghasilkan metode async yang mengembalikan berbagai jenis. Jenis pengembalian asinkron umum mengaktifkan peningkatan performa di pustaka .NET. Karena Task dan Task<TResult> adalah jenis referensi, alokasi memori di jalur kritis performa, terutama ketika alokasi terjadi dalam perulangan yang ketat, dapat berdampak buruk pada performa. Dukungan untuk jenis pengembalian umum berarti Anda dapat mengembalikan jenis nilai ringan alih-alih jenis referensi untuk menghindari lebih banyak alokasi memori.
.NET menyediakan struktur System.Threading.Tasks.ValueTask<TResult> sebagai implementasi ringan dari nilai pengembalian tugas umum. Contoh berikut menggunakan struktur ValueTask<TResult> untuk mengambil nilai dua gulungan dadu.
class Program
{
static readonly Random s_rnd = new Random();
static async Task Main() =>
Console.WriteLine($"You rolled {await GetDiceRollAsync()}");
static async ValueTask<int> GetDiceRollAsync()
{
Console.WriteLine("Shaking dice...");
int roll1 = await RollAsync();
int roll2 = await RollAsync();
return roll1 + roll2;
}
static async ValueTask<int> RollAsync()
{
await Task.Delay(500);
int diceRoll = s_rnd.Next(1, 7);
return diceRoll;
}
}
// Example output:
// Shaking dice...
// You rolled 8
Menulis jenis pengembalian asinkron umum adalah skenario tingkat lanjut, dan ditargetkan untuk digunakan di lingkungan khusus. Pertimbangkan untuk menggunakan jenis Task, Task<T>, dan ValueTask<T>, yang mencakup sebagian besar skenario untuk kode asinkron.
Anda dapat menerapkan atribut AsyncMethodBuilder ke metode asinkron (alih-alih deklarasi jenis pengembalian asinkron) untuk menggantikan pembangun untuk jenis tersebut. Biasanya Anda akan menerapkan atribut ini untuk menggunakan penyusun yang berbeda yang disediakan dalam runtime .NET.
Aliran asinkron dengan IAsyncEnumerable<T>
Metode asinkron mungkin mengembalikan aliran asinkron , yang diwakili oleh IAsyncEnumerable<T>. Aliran asinkron menyediakan cara untuk menghitung item yang dibaca dari aliran saat elemen dihasilkan dalam gugus dengan panggilan asinkron berulang. Contoh berikut menunjukkan metode asinkron yang menghasilkan aliran asinkron:
static async IAsyncEnumerable<string> ReadWordsFromStreamAsync()
{
string data =
@"This is a line of text.
Here is the second line of text.
And there is one more for good measure.
Wait, that was the penultimate line.";
using var readStream = new StringReader(data);
string? line = await readStream.ReadLineAsync();
while (line != null)
{
foreach (string word in line.Split(' ', StringSplitOptions.RemoveEmptyEntries))
{
yield return word;
}
line = await readStream.ReadLineAsync();
}
}
Contoh sebelumnya membaca baris dari string secara asinkron. Setelah setiap baris dibaca, kode menghitung setiap kata dalam string. Penelepon akan menghitung setiap kata menggunakan pernyataan await foreach. Metode menunggu ketika perlu membaca baris berikutnya secara asinkron dari string sumber.