Haruskah saya menghindari penangan acara 'async void'?


119

Saya tahu umumnya dianggap ide yang buruk untuk menggunakan async voidmetode api-dan-lupakan untuk memulai tugas, karena tidak ada jejak tugas yang tertunda dan sulit untuk menangani pengecualian yang mungkin dilemparkan ke dalam metode seperti itu.

Haruskah saya juga menghindari async voidpenanganan acara secara umum ? Sebagai contoh,

private async void Form_Load(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

Saya bisa menulis ulang seperti ini:

Task onFormLoadTask = null; // track the task, can implement cancellation

private void Form_Load(object sender, System.EventArgs e)
{
        this.onFormLoadTask = OnFormLoadTaskAsync(sender, e);
} 

private async Task OnFormLoadTaskAsync(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

Apa saja batuan bawah air untuk penangan acara asinkron, selain kemungkinan masuk kembali?


Anda harus tetapi Anda tidak bisa. Selain itu, semua kehati-hatian yang harus Anda lakukan saat menggunakan async void sudah dibutuhkan oleh penangan kejadian UI.
Paulo Morgado

Dan reentrancy terjadi karena operasi asinkron yang dijalankan oleh event handler dan bukan oleh penggunaan async-await dengan sendirinya.
Paulo Morgado

Jawaban:


153

Pedomannya adalah untuk menghindari async void kecuali saat digunakan dalam penanganan peristiwa, jadi menggunakan async voiddalam penanganan peristiwa tidak masalah.

Yang mengatakan, untuk alasan pengujian unit saya sering suka memfaktorkan logika dari semua async voidmetode. Misalnya,

public async Task OnFormLoadAsync(object sender, EventArgs e)
{
  await Task.Delay(2000);
  ...
}

private async void Form_Load(object sender, EventArgs e)
{
  await OnFormLoadAsync(sender, e);
}

Saya penasaran ... adakah alasan mengapa Anda tidak mengubah Form_Loadakses saja public? Sepertinya kode tersebut akan kurang bertele-tele seperti itu.
InteXX

Ups, sudahlah ... VBer mencoba membaca C # di sini ... Saya baru saja memperhatikan jenis kembalian OnFormLoadAsync. Saya melihat sekarang bahwa ini membuat trik yang berguna. Terima kasih.
InteXX

Semua yang dikatakan, bisakah Anda melihat dan menawarkan pendapat di sini . Terima kasih!
InteXX

2
@ AlexHopeO'Connor: HandledBendera harus disetel secara sinkron; tidak mungkin digunakan asyncuntuk membuat keputusan tentang apakah acara tersebut ditangani atau tidak.
Stephen Cleary

2
@ AlexHopeO'Connor: Sudah lama sejak saya bekerja dengan aplikasi WPF, tetapi saya telah menggunakan solusi yang mirip dengan itu di masa lalu. Yakni membuat ICommand.Executemetode async void; Saya menganggap ini diterima karena ICommand.Executemerupakan logis event handler.
Stephen Cleary

50

Haruskah saya biasanya juga menghindari penangan acara void asinkron?

Umumnya penangan acara adalah satu kasus di mana metode async void bukan bau kode potensial.

Sekarang, jika Anda memang perlu melacak tugas karena suatu alasan, maka teknik yang Anda gambarkan sangat masuk akal.


6

Ya, umumnya hanya kasus async void dari event handler. Jika Anda ingin tahu lebih banyak tentang itu, Anda dapat melihat video hebat di sini di saluran 9

The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task".

ini tautannya


' Penangan acara tingkat atas ' adalah petunjuk penting. Saat menggunakan event handler async void pada event handler tingkat rendah, hal itu dapat menyebabkan masalah besar dengan pengecualian yang tidak tertangkap.
Portikus

Terima kasih untuk tautan videonya, sangat berguna
lsp

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.