'Async void' olay işleyicilerinden kaçınmalı mıyım?


119

async voidGörevlere başlamak için ateşle ve unut yöntemlerini kullanmanın genellikle kötü bir fikir olduğunu biliyorum , çünkü bekleyen görevin izi yok ve böyle bir yöntemin içine atılabilecek istisnaları ele almak zor.

Genelde async voidolay işleyicilerinden de kaçınmalı mıyım ? Örneğin,

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

Bunu şu şekilde yeniden yazabilirim:

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
        // ...
} 

Asenkron olay işleyicileri için olası yeniden girişin yanı sıra su altı kayaları nelerdir?


Yapmalısın ama yapamazsın. Bunun yanı sıra, zaman uyumsuz void kullanırken almanız gereken tüm önlemler, UI olay işleyicileri tarafından zaten gereklidir.
Paulo Morgado

Ve yeniden giriş, async-await'in kendi başına kullanılmasıyla değil, olay işleyicisi tarafından tetiklenen asenkron işlemler nedeniyle gerçekleşir.
Paulo Morgado

Yanıtlar:


153

Yönerge, bir olay işleyicide kullanılmadığı async void sürece kaçınmaktır , bu nedenle async voidbir olay işleyicide kullanmak tamamdır.

Bununla birlikte, birim testi nedenlerinden dolayı, genellikle tüm async voidyöntemlerin mantığını hesaba katmayı seviyorum . Örneğin,

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

Merak ediyorum ... Form_Loaderişimini değiştirmemen için bir neden var publicmı? Görünüşe göre kod bu şekilde daha az ayrıntılı olacak.
InteXX

Oops, boşver ... VBer burada C # okumaya çalışıyor ... Sadece dönüş türünü fark ettim OnFormLoadAsync. Şimdi bunun kullanışlı bir numara olduğunu görüyorum. Teşekkürler.
InteXX

Bütün bunlar, buraya bir bakıp bir fikir verebilir misiniz ? Teşekkürler!
InteXX

2
@ AlexHopeO'Connor: Handledbayrak gerekir eşzamanlı olarak ayarlanabilir; asyncolayın ele alınıp alınmayacağına karar vermek için kullanmak mümkün değildir.
Stephen Cleary

2
@ AlexHopeO'Connor: Bir WPF uygulamasıyla çalışmayalı epey oldu, ancak geçmişte buna benzer çözümler kullandım. Yani, ICommand.Executeyöntemi yap async void; Mantıksal olarak bir olay işleyicisi ICommand.Executeolduğu için bunun kabul edilebilir olduğunu düşünüyorum .
Stephen Cleary

50

Genelde asenkron void olay işleyicilerinden de kaçınmalı mıyım?

Genellikle olay işleyicileri, void async yönteminin potansiyel bir kod kokusu olmadığı durumdur.

Şimdi, herhangi bir nedenle görevi izlemeniz gerekiyorsa, tarif ettiğiniz teknik tamamen mantıklıdır.


6

Evet, genellikle olay işleyicilerinin zaman uyumsuz boşluğu tek durumdur. Bununla ilgili daha fazla bilgi edinmek istiyorsanız, kanal 9'da harika bir videoya göz atabilirsiniz.

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".

bağlantı burada


'En üst düzey olay işleyicileri ' önemli bir ipucudur. Daha düşük seviyeli olay işleyicide zaman uyumsuz void olay işleyicisini kullanırken, yakalanmayan istisnalarla büyük sorunlara neden olabilir.
Portikus

Video bağlantısı için teşekkürler, çok kullanışlı
lsp

5

ReSharper kullanıyorsanız, ücretsiz bir ReCommended Uzantı sizin için yararlı olabilir. "Eşzamansız boşluk" yöntemlerini analiz eder ve uygun olmayan şekilde kullanıldığında vurgular. Uzantı, eşzamansız boşluğun farklı kullanımlarını ayırt edebilir ve burada açıklanan uygun hızlı düzeltmeleri sağlayabilir: ReCommended-Extension wiki .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.