2017-09-14 3 views
0

Ich habe eine Gruppe von Befehlen, die von einer Basisklasse erben. Die Basisklasse hat die folgende Erklärung ab:async Task-Methode, die nicht warten muss

public virtual async Task Execute(object parameter){} 

Vererben Klassen bieten eine Überschreibung dieser Methode und nicht alle von ihnen erwarten Aufgaben. In diesen Fällen generiert der Compiler eine Warnung:

Diese asynchrone Methode fehlt "warten" -Operatoren und wird synchron ausgeführt. Erwägen Sie, den Operator 'erwarten' zu verwenden, um auf nicht blockierende API-Aufrufe zu warten, oder 'awarte Task.Run (...)', um CPU-gebundene Arbeit an einem Hintergrund-Thread auszuführen.

Ist es korrekt, einen vollständigen Rückgabewert der Aufgabe explizit anzugeben?

public override async Task Execute(object parameter) { 
    //code containing no await statements... 
    await Task.CompletedTask; 
} 

Antwort

5

Sie sollten die Verwendung des async Schlüsselwort innen überschriebenen Methoden vermeiden, die auf irgendetwas nicht await tun, und stattdessen nur zurück Task.CompletedTask:

public override Task Execute(object parameter) { 
    //code containing no await statements... 
    return Task.CompletedTask; // or Task.FromResult(0) for older .NET versions 
} 

Dies ist einer der (wenigen) Anwendungsfälle für Solche "verspotteten" Aufgaben, wie Sie aus der looking at this question über Task.FromResult verstehen können. Diese Überlegungen gelten weiterhin für Task.CompletedTask.

+2

I diffed die Ausgabe meines ursprünglichen Codes und die Ausgabe Ihrer empfohlenen Änderungen von dotPeek und sie sind identisch (die Debug-DLL). Ihr Beispiel entfernt auch die Compiler-Warnung, die meine ursprüngliche Motivation war. - Vielen Dank! – jchristof

3

Als Kontrapunkt gibt einen Unterschied in der Art und Weise, wie Ausnahmen behandelt werden.

Wenn eine Ausnahme vom synchronen Code in der Nicht-Version async ausgelöst wird, wird diese Ausnahme direkt an den Aufrufer ausgelöst (sehr ungewöhnlich für Methoden mit asynchronen Signaturen).

Wenn eine Ausnahme aus dem synchronen Code in der async-Version ausgelöst wird, wird diese Ausnahme erfasst und auf die zurückgegebene Task gesetzt (dies ist das erwartete Verhalten für Methoden mit asynchronen Signaturen).

Also, wenn die Methode als solche genannt wird, würden die verschiedenen Implementierungen unterschiedliche Ausnahme Semantik haben:

var task = Execute(parameter); // non-async exceptions raised here 
... 
await task; // async exceptions raised here 

Die meiste Zeit jedoch wird die Methode aufgerufen und sofort erwartete, so dass diese beiden Semantik fusionieren zusammen:

await Execute(parameter); // both async and non-async exceptions raised here 

es wahrscheinlich wird keine Rolle, aber ich glaube, es ist ein wichtiger Unterschied, der sich bewusst sein.

Wenn die Ausnahme Semantik für Sie wichtig sind, dann Sieasync verwenden möchten tun, um eine Zustandsmaschine um den synchronen Code zu generieren, und Sie können die Warnung in Ihrem Code deaktivieren:

#pragma warning disable 1998 // use async keyword to capture exceptions 
public override async Task Execute(object parameter) { 
#pragma warning restore 1998 
    //code containing no await statements... 
}