Sollte ich "async void" -Ereignishandler vermeiden?

118

Ich weiß, dass es im Allgemeinen als schlechte Idee angesehen wird, Fire-and-Forget- async voidMethoden zum Starten von Aufgaben zu verwenden, da die anstehende Aufgabe nicht nachverfolgt werden kann und es schwierig ist, Ausnahmen zu behandeln, die in einer solchen Methode ausgelöst werden könnten.

Sollte ich async voidEvent-Handler generell auch meiden ? Beispielsweise,

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

Ich kann es so umschreiben:

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

Was sind die Unterwasserfelsen für asynchrone Event-Handler neben einem möglichen Wiedereintritt?

avo
quelle
Du solltest, aber du kannst nicht. Darüber hinaus benötigen UI-Ereignishandler bereits alle Sorgfalt, die Sie bei der Verwendung von async void beachten müssen.
Paulo Morgado
Der Wiedereintritt erfolgt aufgrund asynchroner Vorgänge, die vom Ereignishandler ausgelöst werden, und nicht aufgrund der Verwendung von asynchronem Warten allein.
Paulo Morgado

Antworten:

152

Die Richtlinie sollte vermieden werden, async void außer wenn sie in einem Ereignishandler verwendet wird. Daher ist die Verwendung async voidin einem Ereignishandler in Ordnung.

Aus Gründen des Unit-Tests möchte ich jedoch häufig die Logik aller async voidMethoden herausrechnen. Z.B,

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);
}
Stephen Cleary
quelle
Ich bin neugierig ... gibt es einen Grund, warum Sie nicht einfach Form_Loadden Zugriff auf ändern public? Es scheint, als wäre der Code auf diese Weise weniger ausführlich.
InteXX
Hoppla, egal ... VBer versucht hier C # zu lesen ... Ich habe gerade den Rückgabetyp von bemerkt OnFormLoadAsync. Ich sehe jetzt, dass dies ein praktischer Trick ist. Vielen Dank.
InteXX
Alles , was gesagt, könnten Sie einen Blick und eine Stellungnahme bieten hier . Vielen Dank!
InteXX
2
@ AlexHopeO'Connor: Das HandledFlag muss synchron gesetzt werden; Es ist nicht möglich async, eine Entscheidung darüber zu treffen, ob das Ereignis behandelt wird oder nicht.
Stephen Cleary
1
@ AlexHopeO'Connor: Es ist schon eine Weile her, dass ich mit einer WPF-App gearbeitet habe, aber ich habe ähnliche Lösungen wie in der Vergangenheit verwendet. Dh, mach die ICommand.ExecuteMethode async void; Ich halte dies für akzeptabel, da ICommand.Executees sich logischerweise um einen Ereignishandler handelt.
Stephen Cleary
49

Sollte ich generell auch asynchrone Leere-Event-Handler vermeiden?

Im Allgemeinen sind Ereignishandler der einzige Fall, in dem eine nichtige asynchrone Methode kein potenzieller Codegeruch ist.

Wenn Sie die Aufgabe aus irgendeinem Grund verfolgen müssen, ist die von Ihnen beschriebene Technik durchaus sinnvoll.

Eric Lippert
quelle
6

Ja, im Allgemeinen ist die asynchrone Leere von Ereignishandlern der einzige Fall. Wenn Sie mehr darüber erfahren möchten, können Sie sich hier auf Kanal 9 ein großartiges Video ansehen

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

Hier ist der Link

Idrees Khan
quelle
Die ' Top-Level-Event-Handler ' sind ein wichtiger Hinweis. Wenn Sie den asynchronen Void-Ereignishandler im Ereignishandler niedrigerer Ebene verwenden, kann dies zu großen Problemen führen, wenn keine Ausnahmen erfasst werden.
Portikus
Vielen Dank für den
Videolink
5

Wenn Sie ReSharper verwenden, kann eine kostenlose empfohlene Erweiterung hilfreich sein. Es analysiert die "async void" -Methoden und hebt sie hervor, wenn sie unsachgemäß verwendet werden. Die Erweiterung kann verschiedene Verwendungen von asynchroner Leere unterscheiden und geeignete Schnellkorrekturen bereitstellen, die hier beschrieben werden: ReCommended-Extension-Wiki .

Alexander Zwitbaum
quelle