Ich möchte eine asynchrone Methode mit einem out
Parameter wie folgt schreiben :
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
Wie mache ich das in GetDataTaskAsync
?
quelle
Ich möchte eine asynchrone Methode mit einem out
Parameter wie folgt schreiben :
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
Wie mache ich das in GetDataTaskAsync
?
Sie können keine asynchronen Methoden mit ref
oder habenout
Parameter verwenden.
Lucian Wischik erklärt, warum dies in diesem MSDN-Thread nicht möglich ist: http://social.msdn.microsoft.com/Forums/en-US/d2f48a52-e35a-4948-844d-828a1a6deb74/why-async-methods-cannot-have -ref-or-out-Parameter
Warum unterstützen asynchrone Methoden keine Out-by-Reference-Parameter? (oder Referenzparameter?) Dies ist eine Einschränkung der CLR. Wir haben uns entschieden, asynchrone Methoden ähnlich wie Iterator-Methoden zu implementieren - dh durch den Compiler, der die Methode in ein State-Machine-Objekt umwandelt. Die CLR hat keine sichere Möglichkeit, die Adresse eines "out-Parameters" oder eines "Referenzparameters" als Feld eines Objekts zu speichern. Die einzige Möglichkeit, Out-by-Reference-Parameter zu unterstützen, besteht darin, dass die asynchrone Funktion durch ein CLR-Umschreiben auf niedriger Ebene anstelle eines Compiler-Umschreibens ausgeführt wird. Wir haben diesen Ansatz untersucht, und es gab viel zu tun, aber es wäre letztendlich so kostspielig gewesen, dass es niemals passiert wäre.
Eine typische Problemumgehung für diese Situation besteht darin, dass die asynchrone Methode stattdessen ein Tupel zurückgibt. Sie können Ihre Methode als solche neu schreiben:
public async Task Method1()
{
var tuple = await GetDataTaskAsync();
int op = tuple.Item1;
int result = tuple.Item2;
}
public async Task<Tuple<int, int>> GetDataTaskAsync()
{
//...
return new Tuple<int, int>(1, 2);
}
Tuple
Alternative. Sehr hilfreich.Tuple
. : PSie können noch nicht
ref
oderout
Parameter inasync
Methoden haben (wie bereits erwähnt).Dies schreit nach einer Modellierung in den Daten, die sich bewegen:
Sie erhalten die Möglichkeit, Ihren Code einfacher wiederzuverwenden, und er ist weitaus lesbarer als Variablen oder Tupel.
quelle
Die C # 7 + -Lösung besteht darin, die implizite Tupelsyntax zu verwenden.
Das Rückgabeergebnis verwendet die für die Methodensignatur definierten Eigenschaftsnamen. z.B:
quelle
Alex legte großen Wert auf Lesbarkeit. Entsprechend ist eine Funktion auch eine Schnittstelle genug, um die zurückgegebenen Typen zu definieren, und Sie erhalten auch aussagekräftige Variablennamen.
Anrufer stellen ein Lambda (oder eine benannte Funktion) bereit, und Intellisense hilft beim Kopieren der Variablennamen vom Delegaten.
Dieser spezielle Ansatz ähnelt einer "Try" -Methode, bei der festgelegt
myOp
wird, ob das Methodenergebnis vorliegttrue
. Ansonsten interessiert es dich nichtmyOp
.quelle
Eine nette Eigenschaft von
out
Parametern ist, dass sie verwendet werden können, um Daten zurückzugeben, selbst wenn eine Funktion eine Ausnahme auslöst. Ich denke, das nächste Äquivalent dazuasync
wäre, ein neues Objekt zu verwenden, um die Daten zu speichern, auf die sowohl dieasync
Methode als auch der Aufrufer verweisen können. Eine andere Möglichkeit wäre, einen Delegierten zu übergeben, wie in einer anderen Antwort vorgeschlagen .Beachten Sie, dass keine dieser Techniken die vom Compiler erzwungene Durchsetzung
out
hat. Das heißt, der Compiler verlangt nicht, dass Sie den Wert für das freigegebene Objekt festlegen oder einen übergebenen Delegaten aufrufen.Hier ist eine Beispiel - Implementierung eines gemeinsames Objekt zu imitieren mit
ref
undout
für die Verwendung mitasync
Methoden und verschiedenen anderen Szenarien , in denenref
undout
nicht zur Verfügung stehen:quelle
Ich liebe das
Try
Muster. Es ist ein ordentliches Muster.Aber es ist eine Herausforderung mit
async
. Das heißt nicht, dass wir keine wirklichen Optionen haben. Hier sind die drei Kernansätze, die Sie fürasync
Methoden in einer Quasi-Version desTry
Musters berücksichtigen können .Ansatz 1 - Struktur ausgeben
Dies sieht am ehesten nach einer Synchronisierungsmethode aus
Try
, die nur atuple
anstelle von abool
mit einemout
Parameter zurückgibt, von dem wir alle wissen, dass er in C # nicht zulässig ist.Bei einem Verfahren , dass die Renditen
true
vonfalse
und nie werfenexception
.Ansatz 2 - Rückrufmethoden übergeben
Wir können
anonymous
Methoden verwenden, um externe Variablen festzulegen. Es ist eine clevere Syntax, wenn auch etwas kompliziert. In kleinen Dosen ist es in Ordnung.Die Methode befolgt die Grundlagen des
Try
Musters, setzt jedochout
Parameter, die in Rückrufmethoden übergeben werden. Es ist so gemacht.Ansatz 3 - Verwenden Sie ContinueWith
Was ist, wenn Sie nur das
TPL
wie vorgesehen verwenden? Keine Tupel. Die Idee hier ist, dass wir Ausnahmen verwenden, umContinueWith
auf zwei verschiedene Pfade umzuleiten .Mit einer Methode, die einen
exception
Fehler auslöst, wenn ein Fehler auftritt. Das ist anders als die Rückgabe von aboolean
. Es ist eine Möglichkeit, mit dem zu kommunizierenTPL
.Wenn die Datei im obigen Code nicht gefunden wird, wird eine Ausnahme ausgelöst. Dies ruft den Fehler auf
ContinueWith
, derTask.Exception
in seinem Logikblock behandelt wird. Ordentlich, was?Viel Glück.
quelle
ContinueWith
Anrufen das erwartete Ergebnis hat? Nach meinem Verständnis wird die zweiteContinueWith
den Erfolg der ersten Fortsetzung überprüfen, nicht den Erfolg der ursprünglichen Aufgabe.Ich hatte das gleiche Problem, wie ich es mag, das Try-Methoden-Muster zu verwenden, das im Grunde nicht mit dem Async-Wait-Paradigma kompatibel zu sein scheint ...
Wichtig für mich ist, dass ich die Try-Methode innerhalb einer einzelnen if-Klausel aufrufen kann und die out-Variablen vorher nicht vordefinieren muss, sondern wie im folgenden Beispiel inline ausführen kann:
Also habe ich folgende Lösung gefunden:
Definieren Sie eine Hilfsstruktur:
Definieren Sie die asynchrone Try-Methode wie folgt:
Rufen Sie die asynchrone Try-Methode folgendermaßen auf:
Für mehrere Out-Parameter können Sie zusätzliche Strukturen definieren (z. B. AsyncOut <T, OUT1, OUT2>) oder ein Tupel zurückgeben.
quelle
Die Einschränkung der
async
Methoden, die keineout
Parameter akzeptieren , gilt nur für die vom Compiler generierten asynchronen Methoden, die mit demasync
Schlüsselwort deklariert wurden. Dies gilt nicht für handgefertigte asynchrone Methoden. Mit anderen Worten, es ist möglich,Task
Rückgabemethoden zu erstellen , dieout
Parameter akzeptieren . Nehmen wir zum Beispiel an, wir haben bereits eineParseIntAsync
Methode, die wirft, und wir möchten eine Methode erstellenTryParseIntAsync
, die nicht wirft. Wir könnten es so umsetzen:Die Verwendung der
TaskCompletionSource
und-ContinueWith
Methode ist etwas umständlich, aber es gibt keine andere Option, da wir die bequeme nicht verwenden könnenawait
Schlüsselwort innerhalb dieser Methode.Anwendungsbeispiel:
Update: Wenn die asynchrone Logik zu komplex ist, um ohne ausgedrückt zu werden
await
, kann sie in einem verschachtelten asynchronen anonymen Delegaten gekapselt werden.TaskCompletionSource
Für denout
Parameter wird weiterhin A benötigt . Es ist möglich, dass derout
Parameter vor Abschluss der Hauptaufgabe abgeschlossen wird, wie im folgenden Beispiel:Dieses Beispiel nimmt die Existenz von drei asynchronen Methoden
GetResponseAsync
,GetRawDataAsync
undFilterDataAsync
daß in Aufeinanderfolge genannt. Derout
Parameter wird nach Abschluss der zweiten Methode abgeschlossen. DieGetDataAsync
Methode könnte folgendermaßen verwendet werden:In diesem vereinfachten Beispiel ist es wichtig,
data
auf das Warten zu wartenrawDataLength
, da derout
Parameter im Falle einer Ausnahme niemals vervollständigt wird.quelle
Ich denke, dass die Verwendung solcher ValueTuples funktionieren kann. Sie müssen jedoch zuerst das ValueTuple NuGet-Paket hinzufügen:
quelle
Hier ist der Code der Antwort von @ dcastro, der für C # 7.0 mit benannten Tupeln und Tupeldekonstruktion geändert wurde, wodurch die Notation optimiert wird:
Einzelheiten zu den neuen benannten Tupeln, Tupelliteralen und Tupeldekonstruktionen finden Sie unter: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/
quelle
Sie können dies tun, indem Sie TPL (Task Parallel Library) verwenden, anstatt direkt das Schlüsselwort await zu verwenden.
quelle