Was wäre die eleganteste Art, eine asynchrone Methode von einem Getter oder Setter in C # aufzurufen?
Hier ist ein Pseudocode, der mir hilft, mich zu erklären.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
Task<T>
, die sofort zurückgegeben wird, eine normale Eigenschaftssemantik aufweist und dennoch die asynchrone Behandlung von Dingen nach Bedarf ermöglicht.Antworten:
Es gibt keinen technischen Grund, warum
async
Eigenschaften in C # nicht zulässig sind. Es war eine gezielte Entwurfsentscheidung, da "asynchrone Eigenschaften" ein Oxymoron sind.Eigenschaften sollten aktuelle Werte zurückgeben. Sie sollten keine Hintergrundoperationen starten.
Wenn jemand eine "asynchrone Eigenschaft" möchte, möchte er normalerweise Folgendes:
async
Methode.async
Factory-Methode für das enthaltende Objekt oder eineasync InitAsync()
Methode. Der datengebundene Wert bleibt so lange bestehen,default(T)
bis der Wert berechnet / abgerufen wurde.AsyncLazy
aus meinem Blog oder meiner AsyncEx-Bibliothek . Dies gibt Ihnen eineawait
fähige Eigenschaft.Update: Ich beschreibe asynchrone Eigenschaften in einem meiner letzten " asynchronen OOP" -Blogposts.
quelle
Dispatcher.CurrentDispatcher.Invoke(new Action(..)
?INotifyPropertyChanged
Sie einfach und entscheiden Sie dann, ob der alte Wert zurückgegeben werden soll oderdefault(T)
während das asynchrone Update ausgeführt wird.NotifyTaskCompletion
aus meinem AsyncEx-Projekt zu verwenden . Oder Sie können Ihre eigenen bauen; es ist nicht so schwer.{Binding PropName.Result}
ist für mich nicht trivial, um es herauszufinden.Sie können es nicht asynchron aufrufen, da es keine Unterstützung für asynchrone Eigenschaften gibt, sondern nur asynchrone Methoden. Daher gibt es zwei Optionen, die beide die Tatsache ausnutzen, dass asynchrone Methoden im CTP eigentlich nur eine Methode sind, die zurückgibt
Task<T>
oderTask
:Oder:
quelle
private async void SetupList() { MyList = await MyAsyncMethod(); }
Dies würde dazu führen, dass MyList gesetzt wird (und dann automatisch bindet, wenn INPC implementiert wird), sobald der asynchrone Vorgang abgeschlossen ist ...getTitle()
...Aufgrund meiner entkoppelten Architektur brauchte ich den Aufruf wirklich, um von der get-Methode zu stammen. Also habe ich mir die folgende Implementierung ausgedacht.
Verwendung: Der Titel befindet sich in einem ViewModel oder einem Objekt, das Sie statisch als Seitenressource deklarieren können. Wenn Sie daran binden, wird der Wert gefüllt, ohne die Benutzeroberfläche zu blockieren, wenn getTitle () zurückkehrt.
quelle
Ich denke, wir können darauf warten, dass der Wert zuerst null zurückgibt und dann den tatsächlichen Wert erhält. Im Fall von Pure MVVM (z. B. PCL-Projekt) halte ich Folgendes für die eleganteste Lösung:
quelle
CS4014: Async method invocation without an await expression
async void
Nur für Top-Level-Handler und dergleichen verwenden." Ich denke, dies kann als "und dergleichen" qualifiziert werden.Sie können
Task
wie folgt verwenden:quelle
Ich dachte. GetAwaiter (). GetResult () war genau die Lösung für dieses Problem, nein? z.B:
quelle
.Result
- es ist nicht asynchron und kann zu Deadlocks führen.Da sich Ihre "asynchrone Eigenschaft" in einem Ansichtsmodell befindet, können Sie AsyncMVVM verwenden :
Es kümmert sich für Sie um den Synchronisationskontext und die Benachrichtigung über Eigenschaftsänderungen.
quelle
Nekromantie.
In .NET Core / NetStandard2 können Sie
Nito.AsyncEx.AsyncContext.Run
anstelle vonSystem.Windows.Threading.Dispatcher.InvokeAsync
:Wenn Sie einfach
System.Threading.Tasks.Task.Run
oderSystem.Threading.Tasks.Task<int>.Run
wählen würden, würde es nicht funktionieren.quelle
Ich denke, mein Beispiel unten folgt möglicherweise dem Ansatz von @ Stephen-Cleary, aber ich wollte ein codiertes Beispiel geben. Dies dient zur Verwendung in einem Datenbindungskontext, beispielsweise Xamarin.
Der Konstruktor der Klasse - oder tatsächlich der Setter einer anderen Eigenschaft, von der er abhängig ist - kann eine asynchrone Leere aufrufen, die die Eigenschaft nach Abschluss der Aufgabe auffüllt, ohne dass ein Warten oder Blockieren erforderlich ist. Wenn es endlich einen Wert erhält, aktualisiert es Ihre Benutzeroberfläche über den NotifyPropertyChanged-Mechanismus.
Ich bin mir nicht sicher, welche Nebenwirkungen es hat, wenn ein Konstruktor eine aysnc-Leere aufruft. Vielleicht wird ein Kommentator die Fehlerbehandlung usw. näher erläutern.
quelle
Als ich auf dieses Problem stieß, führte der Versuch, eine asynchrone Methodensynchronität von einem Setter oder einem Konstruktor aus auszuführen, zu einem Deadlock im UI-Thread, und die Verwendung eines Ereignishandlers erforderte zu viele Änderungen im allgemeinen Design.
Die Lösung bestand, wie so oft, darin, explizit zu schreiben, was ich implizit tun wollte, nämlich einen anderen Thread die Operation abwickeln zu lassen und den Haupt-Thread dazu zu bringen, auf den Abschluss zu warten:
Sie könnten argumentieren, dass ich das Framework missbrauche, aber es funktioniert.
quelle
Ich überprüfe alle Antworten, aber alle haben ein Leistungsproblem.
zum Beispiel in:
Deployment.Current.Dispatcher.InvokeAsync (async () => {Title = warte auf getTitle ();});
Verwenden Sie einen Dispatcher, der keine gute Antwort ist.
Aber es gibt eine einfache Lösung, machen Sie es einfach:
quelle
Sie können die Eigenschaft in ändern
Task<IEnumerable>
und mache so etwas wie:
und benutze es wie auf MyList warten;
quelle