Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Jeśli piszesz klasę z niektórymi operacjami, które mogą powodować zauważalne opóźnienia, rozważ nadanie jej funkcji asynchronicznej przez zaimplementowanie asynchronicznego wzorca opartego na zdarzeniach.
Wzorzec asynchroniczny oparty na zdarzeniach zapewnia ustandaryzowany sposób tworzenia pakietu klasy, która ma funkcje asynchroniczne. Jeśli zaimplementowano przy użyciu klas pomocnika, takich jak AsyncOperationManager, klasa będzie działać poprawnie w dowolnym modelu aplikacji, w tym w ASP.NET, aplikacjach konsolowych i aplikacjach Windows Forms.
Przykład implementujący asynchroniczny wzorzec oparty na zdarzeniach, zobacz How to: Implement a Component That Supports the Event-based Asynchronous Pattern (Instrukcje: implementowanie składnika obsługującego asynchroniczny wzorzec oparty na zdarzeniach).
Dla prostych operacji asynchronicznych odpowiedni może być komponent BackgroundWorker. Aby uzyskać więcej informacji na temat BackgroundWorkerprogramu , zobacz How to: Run an Operation in the Background (Instrukcje: uruchamianie operacji w tle).
Poniższa lista zawiera opis funkcji asynchronicznego wzorca opartego na zdarzeniach omówionego w tym temacie.
Możliwości implementacji wzorca asynchronicznego opartego na zdarzeniach
Nazewnictwo metod asynchronicznych
Opcjonalna obsługa anulowania
Opcjonalne wsparcie dla właściwości IsBusy
Opcjonalnie zapewnij obsługę raportowania postępu
Umożliw obsługę zwracania wyników przyrostowych opcjonalnie
Obsługa parametrów out i ref w metodach
Możliwości implementacji wzorca asynchronicznego opartego na zdarzeniach
Rozważ zaimplementowanie wzorca asynchronicznego opartego na zdarzeniach, gdy:
Klienci klasy nie potrzebują, aby obiekty WaitHandle i IAsyncResult były dostępne dla operacji asynchronicznych, co oznacza, że sondowanie oraz WaitAll lub WaitAny będą musiały być przygotowane przez klienta.
Chcesz, aby operacje asynchroniczne były zarządzane przez klienta za pomocą znanego modelu zdarzenia/delegata.
Każda operacja jest kandydatem do implementacji asynchronicznej, ale należy wziąć pod uwagę te, które powinny powodować długie opóźnienia. Szczególnie odpowiednie są operacje, w których klienci wywołują metodę i są powiadamiani po zakończeniu, bez konieczności dalszej interwencji. Odpowiednie są również operacje, które są uruchamiane w sposób ciągły, okresowo powiadamiając klientów o postępie oraz wynikach przyrostowych lub zmianach stanu.
Aby uzyskać więcej informacji na temat określania, kiedy należy obsługiwać wzorzec asynchroniczny oparty na zdarzeniach, zobacz Wybieranie, kiedy należy zaimplementować wzorzec asynchroniczny oparty na zdarzeniach.
Nazewnictwo metod asynchronicznych
Dla każdej synchronicznej metody MethodName , dla której chcesz podać asynchroniczny odpowiednik:
Zdefiniuj metodę MethodNameAsync , która:
Zwraca wartość
void
.Przyjmuje te same parametry co metoda MethodName .
Akceptuje wiele wywołań.
Opcjonalnie zdefiniuj przeciążenie metody MethodNameAsync, które jest identyczne z MethodNameAsync, ale z dodatkowym parametrem obiektowym o nazwie userState
. Zrób to, jeśli chcesz zarządzać wieloma współbieżnymi wywołaniami metody, w takim przypadku wartość userState
zostanie zwrócona do wszystkich obsług zdarzeń w celu odróżnienia wywołań metody. Możesz również to zrobić po prostu jako miejsce do przechowywania stanu użytkownika na potrzeby późniejszego pobierania.
Dla każdej oddzielnej sygnatury metody MethodNameAsync :
Zdefiniuj następujące zdarzenie w tej samej klasie co metoda:
Public Event MethodNameCompleted As MethodNameCompletedEventHandler
public event MethodNameCompletedEventHandler MethodNameCompleted;
Zdefiniuj następujący delegat i AsyncCompletedEventArgs. Prawdopodobnie zostaną one zdefiniowane poza samą klasą, ale w tej samej przestrzeni nazw.
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; } }
Upewnij się, że klasa MethodNameCompletedEventArgs uwidacznia jego składowe jako właściwości tylko do odczytu, a nie pola, ponieważ pola uniemożliwiają powiązanie danych.
Nie należy definiować żadnych AsyncCompletedEventArgsklas pochodnych dla metod, które nie generują wyników. Wystarczy po prostu użyć AsyncCompletedEventArgs.
Uwaga / Notatka
Jest to całkowicie akceptowalne, jeśli jest to możliwe i odpowiednie, aby ponownie używać typów delegatów i AsyncCompletedEventArgs. W takim przypadku nazewnictwo nie będzie zgodne z nazwą metody, ponieważ dany delegat i AsyncCompletedEventArgs nie będzie powiązany z jedną metodą.
Opcjonalna obsługa anulowania
Jeśli klasa będzie obsługiwać anulowanie operacji asynchronicznych, anulowanie powinno zostać ujawnione klientowi zgodnie z poniższym opisem. Przed zdefiniowaniem wsparcia przy anulowaniu należy osiągnąć dwa punkty decyzyjne.
- Czy Twoja klasa, w tym zmiany planowane w przyszłości, ma tylko jedną operację asynchroniczną, która umożliwia anulowanie?
- Czy operacje asynchroniczne, które obsługują anulowanie, obsługują wiele oczekujących operacji? Oznacza to, czy metoda MethodNameAsync przyjmuje parametr
userState
i czy zezwala na wiele wywołań przed oczekiwaniem na zakończenie któregokolwiek z nich?
Skorzystaj z odpowiedzi na te dwa pytania w poniższej tabeli, aby określić, jaki powinien być podpis metody anulowania.
Visual Basic
Obsługa wielu równoczesnych operacji | Tylko jedna operacja w danym momencie | |
---|---|---|
Jedna operacja asynchroniczna w całej klasie | Sub MethodNameAsyncCancel(ByVal userState As Object) |
Sub MethodNameAsyncCancel() |
Wiele operacji asynchronicznych w klasie | Sub CancelAsync(ByVal userState As Object) |
Sub CancelAsync() |
C#
Obsługa wielu równoczesnych operacji | Tylko jedna operacja w danym momencie | |
---|---|---|
Jedna operacja asynchroniczna w całej klasie | void MethodNameAsyncCancel(object userState); |
void MethodNameAsyncCancel(); |
Wiele operacji asynchronicznych w klasie | void CancelAsync(object userState); |
void CancelAsync(); |
Jeśli zdefiniujesz metodę CancelAsync(object userState)
, klienci muszą zachować ostrożność podczas wybierania ich wartości stanu, aby umożliwić im rozróżnienie między wszystkimi metodami asynchronicznymi wywoływanymi w obiekcie, a nie tylko między wszystkimi wywołaniami pojedynczej metody asynchronicznej.
Decyzja o nazwaniu wersji z jedną operacją asynchroniczną methodNameAsyncCancel opiera się na możliwościach łatwiejszego odnalezienia metody w środowisku projektowym, takim jak IntelliSense w Visual Studio. Grupuje to powiązanych członków i odróżnia ich od innych członków, którzy nie mają nic wspólnego z funkcjonalnością asynchroniczną. Jeśli spodziewasz się, że w kolejnych wersjach mogą zostać dodane dodatkowe operacje asynchroniczne, lepiej zdefiniować CancelAsync
.
Nie należy definiować wielu metod z powyższej tabeli w tej samej klasie. To nie będzie miało sensu albo sprawi, że interfejs klasy będzie przeładowany proliferacją metod.
Te metody zazwyczaj będą zwracane natychmiast, a operacja może lub nie może zostać anulowana. W procedurze obsługi zdarzeń dla zdarzenia MethodNameCompleted obiekt MethodNameCompletedEventArgs zawiera Cancelled
pole, którego klienci mogą użyć do określenia, czy nastąpiło anulowanie.
Przestrzegaj semantyki anulowania opisanej w artykule Best Practices for Implement the Event-based Asynchronous Pattern (Najlepsze rozwiązania dotyczące implementowania wzorca asynchronicznego opartego na zdarzeniach).
Opcjonalne wsparcie dla właściwości IsBusy
Jeśli klasa nie obsługuje wielu współbieżnych wywołań, rozważ ujawnienie IsBusy
właściwości. Dzięki temu deweloperzy mogą określić, czy metoda MethodNameAsync jest uruchomiona bez przechwytywania wyjątku od metody MethodNameAsync .
Przestrzegaj semantyki opisanej IsBusy
w artykule Best Practices for Implement the Event-based Asynchronous Pattern (Najlepsze rozwiązania dotyczące implementowania wzorca asynchronicznego opartego na zdarzeniach).
Opcjonalnie zapewnij obsługę raportowania postępu
Często pożądane jest, aby operacja asynchroniczna zgłaszała postęp podczas jej trwania. Wzorzec asynchroniczny oparty na zdarzeniach zawiera wskazówki dotyczące tego działania.
Opcjonalnie zdefiniuj zdarzenie, które ma być wywoływane przez operację asynchroniczną i wywoływane w odpowiednim wątku. Obiekt ProgressChangedEventArgs zawiera wskaźnik postępu o wartości całkowitej, który powinien należeć do przedziału od 0 do 100.
Nadaj temu zdarzeniu nazwę w następujący sposób:
ProgressChanged
jeśli klasa ma wiele operacji asynchronicznych (lub oczekuje się, że wzrośnie, aby uwzględnić wiele operacji asynchronicznych w przyszłych wersjach);MethodNameProgressChanged , jeśli klasa ma jedną operację asynchroniczną.
Ten wybór nazewnictwa jest zgodny z wyborem dokonanym dla metody odwołania, jak opisano w sekcji Opcjonalne wsparcie anulowania.
To zdarzenie powinno używać sygnatury delegata ProgressChangedEventHandler i klasy ProgressChangedEventArgs. Alternatywnie, jeśli można dostarczyć bardziej specyficzny dla domeny wskaźnik postępu (na przykład odczytane bajty i całkowitą liczbę bajtów dla operacji pobierania), należy zdefiniować ProgressChangedEventArgs jako pochodną klasy.
Należy pamiętać, że dla klasy istnieje tylko jedno zdarzenie ProgressChanged
MethodNameProgressChanged, niezależnie od liczby obsługiwanych przez nią metod asynchronicznych. Oczekuje się, że klienci będą używać obiektu przekazanego userState
do metod MethodNameAsync w celu odróżnienia między aktualizacjami postępu na wielu współbieżnych operacjach.
Mogą wystąpić sytuacje, w których wiele operacji wspiera postęp i każda zwraca inny wskaźnik postępu. W takim przypadku pojedyncze ProgressChanged
zdarzenie nie jest odpowiednie i można rozważyć obsługę wielu ProgressChanged
zdarzeń. W tym przypadku należy użyć wzorca nazewnictwa MethodNameProgressChanged dla każdej metody MethodNameAsync.
Przestrzegaj semantyki raportowania postępu opisanej w Najlepsze Praktyki dotyczące implementowania asynchronicznego wzorca opartego na zdarzeniach.
Umożliw obsługę zwracania wyników przyrostowych opcjonalnie
Czasami operacja asynchroniczna może zwracać wyniki przyrostowe przed zakończeniem. Istnieje wiele opcji, których można użyć do obsługi tego scenariusza. Poniżej przedstawiono kilka przykładów.
Klasa operacji jednorazowej
Jeśli klasa obsługuje tylko jedną operację asynchroniczną, a ta operacja może zwrócić wyniki przyrostowe, wówczas:
ProgressChangedEventArgs Rozszerz typ tak, aby przenosił dane wynikowe przyrostowe, i zdefiniuj zdarzenie MethodNameProgressChanged przy użyciu tych rozszerzonych danych.
Zgłoś to zdarzenie MethodNameProgressChanged , gdy istnieje wynik przyrostowy do raportowania.
To rozwiązanie ma zastosowanie wyłącznie do klasy pojedynczej operacji asynchronicznej, ponieważ nie ma problemu, by to samo zdarzenie mogło zwracać wyniki przyrostowe dla "wszystkich operacji", jak czyni to zdarzenie MethodNameProgressChanged.
Klasa wielozadaniowa z jednorodnymi przyrostowymi wynikami
W takim przypadku klasa obsługuje wiele metod asynchronicznych, z których każda może zwracać wyniki przyrostowe, a wszystkie te przyrostowe wyniki mają ten sam typ danych.
Postępuj zgodnie z modelem opisanym powyżej dla klas pojedynczej operacji, ponieważ ta sama EventArgs struktura będzie działać dla wszystkich wyników przyrostowych. Zdefiniuj zdarzenie ProgressChanged
zamiast zdarzenia MethodNameProgressChanged, ponieważ dotyczy to wielu metod asynchronicznych.
Klasa wielokrotnej operacji z heterogenicznymi wynikami przyrostowymi
Jeśli klasa obsługuje wiele metod asynchronicznych, każdy zwraca inny typ danych, należy wykonać następujące czynności:
Oddziel raportowanie wyników przyrostowych od raportowania postępu.
Zdefiniuj oddzielne zdarzenie MethodNameProgressChanged z odpowiednimi parametrami dla każdej metody asynchronicznej, aby obsługiwać stopniowe wyniki danych tej metody.
Wywołaj tę procedurę obsługi zdarzeń w odpowiednim wątku zgodnie z opisem w najlepszych praktykach implementowania wzorca asynchronicznego opartego na zdarzeniach).
Obsługa parametrów out i ref w metodach
Chociaż stosowanie out
i ref
jest ogólnie odradzane w .NET, oto zasady, których należy przestrzegać, gdy są obecne:
Biorąc pod uwagę synchroniczną metodę MethodName:
out
parametry methodName nie powinny być częścią metody MethodNameAsync. Zamiast tego powinny one być częścią MethodNameCompletedEventArgs o takiej samej nazwie jak jej odpowiednik parametru w MethodName (chyba że istnieje bardziej odpowiednia nazwa).ref
parametry MethodName powinny pojawić się jako część MethodNameAsync i jako część MethodNameCompletedEventArgs z tą samą nazwą jak jego odpowiednik parametru w MethodName (chyba że istnieje bardziej odpowiednia nazwa).
Na przykład, biorąc pod uwagę:
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);
Metoda asynchroniczna i jej AsyncCompletedEventArgs klasa będą wyglądać następująco:
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; };
}
Zobacz także
- ProgressChangedEventArgs
- AsyncCompletedEventArgs
- Instrukcje: implementowanie składnika obsługującego wzorzec asynchroniczny oparty na zdarzeniach
- Instrukcje: uruchamianie operacji w tle
- Instrukcje: implementowanie formularza korzystającego z operacji w tle
- Podejmowanie decyzji o tym, kiedy należy zaimplementować wzorzec asynchroniczny oparty na zdarzeniach
- Najlepsze rozwiązania dotyczące implementowania wzorca asynchronicznego opartego na zdarzeniach
- Asynchroniczny wzorzec oparty na zdarzeniach (EAP)