Ich arbeite mit einem Warnfenster (Telerik WPF), das normalerweise asynchron angezeigt wird (Code wird weiterhin ausgeführt, solange es geöffnet ist), und ich möchte es mithilfe von async / await synchronisieren.
Ich arbeite damit, TaskCompletionSource
aber diese Klasse ist generisch und gibt ein Objekt zurück, wie Task<bool>
wenn ich nur eine Ebene Task
ohne Rückgabewert möchte .
public Task<bool> ShowAlert(object message, string windowTitle)
{
var dialogParameters = new DialogParameters { Content = message };
var tcs = new TaskCompletionSource<bool>();
dialogParameters.Closed += (s, e) => tcs.TrySetResult(true);
RadWindow.Alert(dialogParameters);
return tcs.Task;
}
Der Code, der diese Methode aufruft, lautet
await MessageBoxService.ShowAlert("The alert text.")
Wie kann ich eine nicht generische Aufgabe zurückgeben, die ähnlich funktioniert und auf die ich warten kann, bis das dialogParameters.Closed
Ereignis ausgelöst wird? Ich verstehe, dass ich das bool
, was in diesem Code zurückgegeben wird, einfach ignorieren könnte . Ich suche nach einer anderen Lösung.
quelle
void
als Typparameter akzeptiert würde, müssten Sie diese Verzerrungen nicht ausführen.object
overbool
(wie in Stephens Antwort) ist, dass diesbool
bedeuten könnte, dass es eine Bedeutung gibt.Wenn Sie keine Informationen verlieren möchten, besteht der übliche Ansatz darin,
TaskCompletionSource<object>
ein Ergebnis von zu verwenden und zu vervollständigennull
. Dann geben Sie es einfach alsTask
.quelle
Task.FromException
wurde in .NET 4.6 hinzugefügt..NET 5 hat eine nicht generische
TaskCompletionSource
.Es wurde in dieser Pull-Anfrage hinzugefügt: https://github.com/dotnet/runtime/pull/37452/files#diff-4a72dcb26e2d643c337baef9f64312f3
quelle
Nito.AsyncEx implementiert eine nicht generische
TaskCompletionSource
Klasse, die Herrn @StephenCleary oben gutgeschrieben wurde.quelle
TaskCompletionSource
wird verwendet, um eine asynchrone Schnittstelle zum Synchronisieren von Code mit Ereignissen und dergleichen bereitzustellen. Sie können eineTaskCompletionSource.Task
Geldstrafe abwarten, sind sich also nicht sicher, wo das Problem liegt?TaskCompletionSource
Ihrer Information , die nicht generische Version von wurde in Version 5 der AsyncEx-Bibliothek entfernt: github.com/StephenCleary/AsyncEx/issues/176Von @ Kevin Kalitowski
In diesem Dokument gibt es ein Beispiel, das sich meiner Meinung nach mit dem Problem befasst, wie Kevin betont. Dies ist das Beispiel:
public static Task Delay(int millisecondsTimeout) { var tcs = new TaskCompletionSource<bool>(); new Timer(self => { ((IDisposable)self).Dispose(); tcs.TrySetResult(true); }).Change(millisecondsTimeout, -1); return tcs.Task; }
Zuerst dachte ich, es sei nicht gut, weil man den Modifikator "async" ohne eine Kompilierungsnachricht nicht direkt zur Methode hinzufügen kann. Wenn Sie die Methode jedoch geringfügig ändern, wird die Methode mit async / await kompiliert:
public async static Task Delay(int millisecondsTimeout) { var tcs = new TaskCompletionSource<bool>(); new Timer(self => { ((IDisposable)self).Dispose(); tcs.TrySetResult(true); }).Change(millisecondsTimeout, -1); await tcs.Task; }
Edit: Zuerst dachte ich, ich wäre über den Buckel gekommen. Wenn ich jedoch den entsprechenden Code in meiner App ausgeführt habe, lässt dieser Code die App nur hängen, wenn sie auf tcs.Task; wartet. Daher glaube ich immer noch, dass dies ein schwerwiegender Konstruktionsfehler in der asynchronen / wartenden c # -Syntax ist.
quelle
await
GoAsync () bearbeitet:private static async Task GoAsync() { Console.WriteLine($"Starting await at: {DateTime.Now.ToLongTimeString()}"); await Delay(3000); Console.WriteLine($"Got past await at: {DateTime.Now.ToLongTimeString()}"); }
await tcs.Task.ConfigureAwait(false)
stattdessen.RunContinuationsAsynchronously
Option.