Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Wenn Sie eine Klasse mit einigen Vorgängen schreiben, die möglicherweise spürbare Verzögerungen verursachen, sollten Sie die asynchrone Funktionalität durch Implementieren des ereignisbasierten asynchronen Musters in Betracht ziehen.
Das ereignisbasierte asynchrone Muster bietet eine standardisierte Methode zum Packen einer Klasse mit asynchronen Features. Wenn sie mit Hilfsklassen wie AsyncOperationManagerz. B. implementiert wird, funktioniert Ihre Klasse ordnungsgemäß unter einem beliebigen Anwendungsmodell, einschließlich ASP.NET, Konsolenanwendungen und Windows Forms-Anwendungen.
Ein Beispiel, in dem das ereignisbasiertes asynchrone Muster implementiert wird, finden Sie unter Vorgehensweise: Übersicht über ereignisbasierte asynchrone Muster.
Für einfache asynchrone Vorgänge könnte die BackgroundWorker Komponente geeignet sein. Weitere Informationen zu BackgroundWorker finden Sie unter Vorgehensweise: Eine Operation im Hintergrund ausführen.
In der folgenden Liste werden die Features des ereignisbasierten asynchronen Musters beschrieben, das in diesem Thema erläutert wird.
Möglichkeiten für die Implementierung des ereignisbasierten asynchronen Musters
Benennen asynchroner Methoden
Optionales Unterstützen von Abbruch
Optionales Unterstützen der „IsBusy“-Eigenschaft
Optional Unterstützung für die Statusberichterstattung bereitstellen
Optionales Unterstützen der Rückgabe von inkrementellen Ergebnissen
Verarbeiten von „out“- und „ref“-Parametern in Methoden
Möglichkeiten für die Implementierung des ereignisbasierten asynchronen Musters
Erwägen Sie die Implementierung des ereignisbasierten asynchronen Musters in folgenden Fällen:
Clients einer Klasse benötigen keine WaitHandle- und IAsyncResult-Objekte, die für asynchrone Vorgänge verfügbar sind, d.h. Abfragen und WaitAll oder WaitAny müssen vom Client erzeugt werden.
Sie möchten, dass asynchrone Vorgänge vom Client mit dem vertrauten Ereignis-/Delegatmodell verwaltet werden.
Jeder Vorgang ist ein Kandidat für eine asynchrone Implementierung, aber diejenigen, die erwarten, dass lange Wartezeiten auftreten, sollten berücksichtigt werden. Besonders geeignet sind Vorgänge, bei denen Kunden eine Methode aufrufen und nach Abschluss benachrichtigt werden, ohne dass weitere Eingriffe erforderlich sind. Geeignet sind außerdem Vorgänge, die durchgängig ausgeführt werden und dabei Clients regelmäßig über Fortschritte, inkrementelle Ergebnisse oder Zustandsänderungen benachrichtigen.
Weitere Informationen zur Entscheidung, wann das ereignisbasierte asynchrone Muster unterstützt werden soll, finden Sie unter Entscheiden, wann das ereignisbasierte asynchrone Muster implementiert werden soll.
Benennen asynchroner Methoden
Für jede synchrone Methode MethodName , für die Sie ein asynchrones Gegenstück bereitstellen möchten:
Definieren Sie eine MethodNameAsync-Methode , die:
Gibt
void
zurück.Verwendet dieselben Parameter wie die MethodName-Methode .
Akzeptiert mehrere Aufrufe.
Definieren Sie optional eine MethodNameAsync-Überladung, identisch mit MethodNameAsync, aber mit einem zusätzlichen Parameter mit Objektwert.userState
Führen Sie dies aus, wenn Sie bereit sind, mehrere gleichzeitige Aufrufe Ihrer Methode zu verwalten. In diesem Fall wird der userState
Wert an alle Ereignishandler zurückgestellt, um Aufrufe der Methode zu unterscheiden. Sie können dies auch einfach als Ort zum Speichern des Benutzerzustands für einen späteren Abruf auswählen.
Für jede separate MethodNameAsync-Methodensignatur :
Definieren Sie das folgende Ereignis in derselben Klasse wie die Methode:
Public Event MethodNameCompleted As MethodNameCompletedEventHandler
public event MethodNameCompletedEventHandler MethodNameCompleted;
Den folgenden Delegaten und AsyncCompletedEventArgs. Diese werden wahrscheinlich außerhalb der Klasse selbst definiert, aber im selben Namespace.
Public Delegate Sub MethodNameCompletedEventHandler( _ ByVal sender As Object, _ ByVal e As MethodNameCompletedEventArgs) Public Class MethodNameCompletedEventArgs Inherits System.ComponentModel.AsyncCompletedEventArgs Public ReadOnly Property Result() As MyReturnType End Property
public delegate void MethodNameCompletedEventHandler(object sender, MethodNameCompletedEventArgs e); public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { public MyReturnType Result { get; } }
Stellen Sie sicher, dass die MethodNameCompletedEventArgs-Klasse ihre Member als schreibgeschützte Eigenschaften und nicht als Felder verfügbar macht, da Felder die Datenbindung verhindern.
Definieren AsyncCompletedEventArgsSie keine abgeleiteten Klassen für Methoden, die keine Ergebnisse erzeugen. Verwenden Sie einfach eine Instanz von AsyncCompletedEventArgs selbst.
Hinweis
Es ist durchaus akzeptabel, wenn machbar und angemessen, Delegaten und AsyncCompletedEventArgs-Typen wiederzuverwenden. In diesem Fall ist die Benennung nicht so konsistent wie mit dem Methodennamen, da ein bestimmter Delegat und AsyncCompletedEventArgs nicht an eine einzelne Methode gebunden sind.
Optionales Unterstützen von Abbruch
Wenn Ihre Klasse das Abbrechen asynchroner Vorgänge unterstützt, sollte der Abbruch für den Client verfügbar gemacht werden, wie unten beschrieben. Es gibt zwei Entscheidungspunkte, die erreicht werden müssen, bevor Sie ihre Stornierungsunterstützung definieren:
- Hat die Klasse, einschließlich zukünftiger zu erwartender Erweiterungen, nur einen asynchronen Vorgang, der Abbruch unterstützt?
- Können die asynchronen Vorgänge, die den Abbruch unterstützen, mehrere ausstehende Vorgänge unterstützen? Das heißt, nimmt die MethodNameAsync-Methode einen
userState
Parameter und erlaubt sie mehrere Aufrufe, bevor auf den Abschluss gewartet wird?
Verwenden Sie die Antworten auf diese beiden Fragen in der nachstehenden Tabelle, um zu bestimmen, welche Signatur für Ihre Abbruchmethode gelten soll.
Visual Basic
Mehrere gleichzeitige Vorgänge werden unterstützt | Nur immer jeweils ein Vorgang | |
---|---|---|
Eine asynchrone Operation in der gesamten Klasse | Sub MethodNameAsyncCancel(ByVal userState As Object) |
Sub MethodNameAsyncCancel() |
Mehrere Asynchrone Vorgänge in der Klasse | Sub CancelAsync(ByVal userState As Object) |
Sub CancelAsync() |
C#
Mehrere gleichzeitige Vorgänge werden unterstützt | Nur immer jeweils ein Vorgang | |
---|---|---|
Eine asynchrone Operation in der gesamten Klasse | void MethodNameAsyncCancel(object userState); |
void MethodNameAsyncCancel(); |
Mehrere Asynchrone Vorgänge in der Klasse | void CancelAsync(object userState); |
void CancelAsync(); |
Wenn Sie die CancelAsync(object userState)
Methode definieren, müssen Clients beim Auswählen ihrer Statuswerte vorsichtig sein, damit sie zwischen allen asynchronen Methoden unterscheiden können, die für das Objekt aufgerufen werden, und nicht nur zwischen allen Aufrufen einer einzelnen asynchronen Methode.
Die Entscheidung, die Single-async-Operation-Version MethodNameAsyncCancel zu benennen, basiert darauf, die Methode in einer Entwurfsumgebung wie dem IntelliSense von Visual Studio einfacher zu ermitteln. Dadurch werden die zugehörigen Mitglieder gruppiert und von anderen Mitgliedern unterschieden, die nichts mit asynchroner Funktionalität zu tun haben. Wenn Sie davon ausgehen, dass in nachfolgenden Versionen möglicherweise zusätzliche asynchrone Vorgänge hinzugefügt werden, ist es besser zu definieren CancelAsync
.
Definieren Sie nicht mehrere Methoden aus der obigen Tabelle in derselben Klasse. Das wird nicht sinnvoll sein, oder es wird die Klassenschnittstelle mit einer Verbreitung von Methoden überladen.
Diese Methoden führen üblicherweise sofort eine Rückkehr aus, und der Vorgang wird möglicherweise tatsächlich abgebrochen (oder nicht). Im Ereignishandler für das MethodNameCompleted-Ereignis enthält das MethodNameCompletedEventArgs-Objekt ein Cancelled
Feld, mit dem Clients bestimmen können, ob der Abbruch aufgetreten ist.
Befolgen Sie die in Best Practices für die Implementierung des ereignisbasierten asynchronen Musters dargelegte Abbruchsemantik.
Optionales Unterstützen der „IsBusy“-Eigenschaft
Unterstützt die Klasse nicht mehrere gleichzeitige Aufrufe, sollten Sie eine IsBusy
-Eigenschaft verfügbar machen. Auf diese Weise können Entwickler ermitteln, ob eine MethodNameAsync-Methode ausgeführt wird, ohne eine Ausnahme von der MethodNameAsync-Methode abzufangen.
Halten Sie sich an die IsBusy
in best Practices für die Implementierung des ereignisbasierten asynchronen Musters beschriebenen Semantik.
Optional Unterstützung für die Statusberichterstattung bereitstellen
Es ist häufig wünschenswert, dass ein asynchroner Vorgang den Fortschritt während des Vorgangs meldet. Das ereignisbasierte asynchrone Muster enthält eine Richtlinie dafür.
Definieren Sie optional ein Ereignis, das vom asynchronen Vorgang ausgelöst und im entsprechenden Thread aufgerufen wird. Das ProgressChangedEventArgs Objekt enthält eine Statusanzeige mit ganzzahligen Werten, die voraussichtlich zwischen 0 und 100 liegt.
Benennen Sie dieses Ereignis wie folgt:
ProgressChanged
wenn die Klasse über mehrere asynchrone Vorgänge verfügt (oder voraussichtlich wächst, um mehrere asynchrone Vorgänge in zukünftigen Versionen einzuschließen);MethodNameProgressChanged , wenn die Klasse über einen einzelnen asynchronen Vorgang verfügt.
Diese Benennungskonvention entspricht derjenigen für die Abbruchmethode, wie im Abschnitt „Optionales Unterstützen von Abbruch“ beschrieben.
Dieses Ereignis sollte die Stellvertretungssignatur ProgressChangedEventHandler und die ProgressChangedEventArgs Klasse verwenden. Für den Fall, dass eine bereichsspezifischere Statusanzeige bereitgestellt werden kann (beispielsweise gelesene Bytes und die Gesamtanzahl der Bytes für einen Downloadvorgang), sollten Sie eine abgeleitete Klasse von ProgressChangedEventArgs definieren.
Beachten Sie, dass es nur ein oder ein ProgressChanged
MethodNameProgressChanged-Ereignis für die Klasse gibt, unabhängig von der Anzahl der von ihr unterstützten asynchronen Methoden. Es wird erwartet, dass Clients das Objekt userState
verwenden, das an die MethodName-Async-Methoden übergeben wird, um Fortschrittsaktualisierungen für mehrere gleichzeitige Vorgänge zu unterscheiden.
Es kann Situationen geben, in denen mehrere Vorgänge den Fortschritt unterstützen und jeweils einen anderen Indikator für den Fortschritt zurückgeben. In diesem Fall ist ein einzelnes ProgressChanged
-Ereignis nicht geeignet, und Sie könnten in Betracht ziehen, mehrere ProgressChanged
-Ereignisse zu unterstützen. Verwenden Sie in diesem Fall für jede MethodNameAsync-Methode ein Benennungsmuster von MethodNameProgressChanged.
Halten Sie sich an die Semantik zur Fortschrittsberichterstattung, wie in Beste Praktiken zur Implementierung des ereignisbasierten asynchronen Musters beschrieben.
Optionales Unterstützen der Rückgabe von inkrementellen Ergebnissen
Manchmal kann ein asynchroner Vorgang vor abschluss inkrementelle Ergebnisse zurückgeben. Es gibt eine Reihe von Optionen, die verwendet werden können, um dieses Szenario zu unterstützen. Einige Beispiele folgen.
Klasse mit einem einzigen Vorgang
Wenn Ihre Klasse nur einen einzelnen asynchronen Vorgang unterstützt und dieser Vorgang in der Lage ist, inkrementelle Ergebnisse zurückzugeben, dann:
Erweitern Sie den ProgressChangedEventArgs Typ, um die inkrementellen Ergebnisdaten zu tragen, und definieren Sie ein MethodNameProgressChanged-Ereignis mit diesen erweiterten Daten.
Lösen Sie dieses MethodNameProgressChanged-Ereignis aus, sobald ein zu berichtendes inkrementelles Ergebnis vorliegt.
Diese Lösung gilt speziell für eine Einzel-Async-Operation-Klasse, da es kein Problem mit demselben Ereignis gibt, das inkrementelle Ergebnisse für "alle Vorgänge" zurückgibt, wie es das MethodNameProgressChanged-Ereignis tut.
Klasse mit mehreren Vorgängen und homogenen inkrementellen Ergebnissen
In diesem Fall unterstützt Ihre Klasse mehrere asynchrone Methoden, die jeweils inkrementelle Ergebnisse zurückgeben können, und diese inkrementellen Ergebnisse weisen alle denselben Datentyp auf.
Folgen Sie dem oben beschriebenen Modell für Einzelvorgangsklassen, da dieselbe EventArgs Struktur für alle inkrementellen Ergebnisse funktioniert. Definieren Sie ein ProgressChanged
Ereignis anstelle eines MethodNameProgressChanged-Ereignisses , da es auf mehrere asynchrone Methoden angewendet wird.
Klasse mit mehreren Vorgängen und heterogenen inkrementellen Ergebnissen
Wenn Ihre Klasse mehrere asynchrone Methoden unterstützt, sollten Sie jeweils einen anderen Datentyp zurückgeben:
Trennen Sie die inkrementelle Ergebnisberichterstattung von der Fortschrittsberichterstattung.
Definieren Sie ein separates MethodNameProgressChanged-Ereignis , das für jede asynchrone Methode geeignet EventArgs ist, um die inkrementellen Ergebnisdaten dieser Methode zu behandeln.
Rufen Sie diesen Ereignishandler im entsprechenden Thread auf, wie in best Practices für die Implementierung des ereignisbasierten asynchronen Musters beschrieben.
Verarbeiten von „out“- und „ref“-Parametern in Methoden
Obwohl die Verwendung von out
und ref
im Allgemeinen in .NET abgeraten wird, sind die folgenden Regeln zu beachten, wenn sie vorhanden sind:
Bei einer synchronen Methode MethodName:
out
Parameter von MethodName sollten kein Teil von MethodNameAsync sein. Stattdessen sollten sie Teil von "MethodNameCompletedEventArgs " mit demselben Namen sein wie dessen Parameteräquivalent in MethodName (es sei denn, es gibt einen passenderen Namen).ref
Parameter von MethodName sollten als Teil von MethodNameAsync erscheinen und als Teil von MethodNameCompletedEventArgs mit demselben Namen wie sein Parameteräquivalent in MethodName (es sei denn, es gibt einen passenderen Namen).
Angenommen, dies liegt vor:
Public Function MethodName(ByVal arg1 As String, ByRef arg2 As String, ByRef arg3 As String) As Integer
public int MethodName(string arg1, ref string arg2, out string arg3);
Ihre asynchrone Methode und ihre AsyncCompletedEventArgs Klasse würden wie folgt aussehen:
Public Sub MethodNameAsync(ByVal arg1 As String, ByVal arg2 As String)
Public Class MethodNameCompletedEventArgs
Inherits System.ComponentModel.AsyncCompletedEventArgs
Public ReadOnly Property Result() As Integer
End Property
Public ReadOnly Property Arg2() As String
End Property
Public ReadOnly Property Arg3() As String
End Property
End Class
public void MethodNameAsync(string arg1, string arg2);
public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
public int Result { get; };
public string Arg2 { get; };
public string Arg3 { get; };
}
Siehe auch
- ProgressChangedEventArgs
- AsyncCompletedEventArgs
- Vorgehensweise: Implementieren einer Komponente, die das ereignisbasierte asynchrone Muster unterstützt
- So führen Sie einen Vorgang im Hintergrund aus
- Vorgehensweise: Implementieren eines Formulars, das eine Hintergrundoperation verwendet
- Entscheiden, wann das ereignisbasierte asynchrone Muster implementiert werden soll
- Bewährte Methoden für die Implementierung des ereignisbasierten asynchronen Musters
- Ereignisbasiertes asynchrones Muster (EAP)