Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wzorzec asynchroniczny oparty na zdarzeniach zapewnia skuteczny sposób eksponowania asynchronicznego zachowania w klasach, z znajomymi zdarzeniami i semantyką delegatów. Aby zaimplementować wzorzec asynchroniczny oparty na zdarzeniach, należy przestrzegać określonych wymagań behawioralnych. W poniższych sekcjach opisano wymagania i wskazówki, które należy wziąć pod uwagę podczas implementowania klasy zgodnej ze wzorcem asynchronicznym opartym na zdarzeniach.
Aby zapoznać się z omówieniem, zobacz Implementowanie wzorca asynchronicznego opartego na zdarzeniach.
Wymagane gwarancje zachowania
W przypadku zaimplementowania wzorca asynchronicznego opartego na zdarzeniach należy podać szereg gwarancji, aby upewnić się, że klasa będzie działać prawidłowo, a klienci klasy mogą polegać na takim zachowaniu.
Ukończenie
Zawsze wywołaj procedurę obsługi zdarzeń MethodNameCompleted po pomyślnym zakończeniu, błędzie lub anulowaniu. Aplikacje nigdy nie powinny napotkać sytuacji, w której pozostają bezczynne i nigdy nie zostają ukończone. Jednym wyjątkiem od tej reguły jest to, że sama operacja asynchroniczna została zaprojektowana tak, aby nigdy nie została ukończona.
Zakończono zdarzenie i argumenty zdarzenia
Dla każdej oddzielnej metody MethodNameAsync zastosuj następujące wymagania projektowe:
Zdefiniuj zdarzenie MethodNameCompleted w tej samej klasie co metoda.
Zdefiniuj klasę EventArgs i towarzyszący delegat dla zdarzenia MethodNameCompleted, które pochodzą z klasy AsyncCompletedEventArgs. Domyślna nazwa klasy powinna mieć postać MethodNameCompletedEventArgs.
Upewnij się, że EventArgs klasa jest specyficzna dla zwracanych wartości metody MethodName . W przypadku korzystania z EventArgs klasy nigdy nie należy wymagać od deweloperów rzutowania wyniku.
Poniższy przykład kodu pokazuje odpowiednio dobrą i złą implementację tego wymagania projektowego.
// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
DemoType result = e.Result;
}
// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
DemoType result = (DemoType)(e.Result);
}
Nie należy definiować klasy EventArgs dla metod zwracających
void. Zamiast tego użyj wystąpienia klasy AsyncCompletedEventArgs.Upewnij się, że zawsze zgłaszasz zdarzenie MethodNameCompleted . To zdarzenie powinno zostać zgłoszone po pomyślnym zakończeniu, błędzie lub anulowaniu. Aplikacje nigdy nie powinny napotkać sytuacji, w której pozostają bezczynne i nigdy nie zostają ukończone.
Upewnij się, że przechwytujesz wszelkie wyjątki występujące w operacji asynchronicznej i przypisz przechwycony wyjątek do właściwości Error.
Jeśli wystąpił błąd podczas wykonywania zadania, wyniki nie powinny być dostępne. Error właściwość nie jest
null, upewnij się, że uzyskiwanie dostępu do jakiejkolwiek właściwości w strukturze EventArgs zgłasza wyjątek. RaiseExceptionIfNecessary Użyj metody , aby przeprowadzić tę weryfikację.Modelowanie limitu czasu jako błędu. Gdy wystąpi przekroczenie limitu czasu, zgłoś zdarzenie MethodNameCompleted i przypisz TimeoutException do właściwości Error.
Jeśli klasa obsługuje wiele współbieżnych wywołań, upewnij się, że zdarzenie MethodNameCompleted zawiera odpowiedni
userSuppliedStateobiekt.Upewnij się, że zdarzenie MethodNameCompleted jest wywoływane w odpowiednim wątku i w odpowiednim czasie w cyklu życia aplikacji. Aby uzyskać więcej informacji, zobacz sekcję Wątkowanie i konteksty.
Jednoczesne wykonywanie operacji
Jeśli klasa obsługuje wiele współbieżnych wywołań, umożliw deweloperowi odrębne śledzenie każdego wywołania, definiując przeciążenie MethodNameAsync, które przyjmuje parametr stanu o wartości obiektu lub identyfikator zadania o nazwie
userSuppliedState. Ten parametr powinien zawsze być ostatnim parametrem w podpisie metody MethodNameAsync .Jeśli Twoja klasa definiuje przeciążenie MethodNameAsync, które przyjmuje parametr stanu jako obiekt lub identyfikator zadania, pamiętaj, aby śledzić trwałość operacji związanej z tym identyfikatorem zadania oraz upewnij się, że przekażesz go ponownie do procedury obsługi ukończenia. Dostępne są klasy pomocnicze, które ułatwiają pomoc. Aby uzyskać więcej informacji na temat zarządzania współbieżnością, zobacz How to: Implement a Component That Supports the Event-based Asynchronous Pattern (Instrukcje: implementowanie składnika obsługującego wzorzec asynchroniczny oparty na zdarzeniach).
Jeśli klasa definiuje metodę MethodNameAsync bez parametru stanu i nie obsługuje wielu współbieżnych wywołań, upewnij się, że każda próba wywołania MethodNameAsync przed ukończeniem poprzedniej wywołania MethodNameAsync zgłasza błąd InvalidOperationException.
Ogólnie rzecz biorąc, nie zgłaszaj wyjątku, jeśli metoda MethodNameAsync bez parametru
userSuppliedStatejest wywoływana wiele razy, aby istnieje wiele zaległych operacji. Możesz zgłosić wyjątek, gdy klasa jawnie nie może obsłużyć tej sytuacji, ale zakładajmy, że deweloperzy mogą obsługiwać te liczne nierozróżnialne wywołania zwrotne.
Uzyskiwanie dostępu do wyników
Jeśli wystąpił błąd podczas wykonywania operacji asynchronicznej, wyniki nie powinny być dostępne. Upewnij się, że próba uzyskania dostępu do jakiejkolwiek właściwości w obiekcie AsyncCompletedEventArgs powoduje zgłoszenie wyjątku wskazanego przez Error, gdy
nullnie jest Error. Klasa AsyncCompletedEventArgs udostępnia metodę RaiseExceptionIfNecessary w tym celu.Upewnij się, że każda próba uzyskania dostępu do wyniku zgłasza informację InvalidOperationException o anulowaniu operacji. AsyncCompletedEventArgs.RaiseExceptionIfNecessary Użyj metody , aby przeprowadzić tę weryfikację.
Raportowanie postępu
Obsługa raportowania postępu, jeśli to możliwe. To umożliwia deweloperom zapewnienie lepszego doświadczenia użytkownika aplikacji przy użyciu klasy.
W przypadku zaimplementowania zdarzenia ProgressChanged lub MethodNameProgressChanged upewnij się, że nie ma żadnych takich zdarzeń zgłoszonych dla określonej operacji asynchronicznej po wywołaniu zdarzenia MethodNameCompleted tej operacji.
Jeśli standard ProgressChangedEventArgs jest wypełniany, upewnij się, aby ProgressPercentage zawsze można było interpretować jako wartość procentową. Wartość procentowa nie musi być dokładna, ale powinna reprezentować wartość procentową. Jeśli metryka raportowania postępu musi być czymś innym niż wartość procentowa, utwórz klasę z ProgressChangedEventArgs klasy i pozostaw ProgressPercentage wartość 0. Unikaj używania metryki raportowania innej niż wartość procentowa.
Upewnij się, że
ProgressChangedzdarzenie jest wywoływane w odpowiednim wątku i w odpowiednim czasie w cyklu życia aplikacji. Aby uzyskać więcej informacji, zobacz sekcję Wątkowanie i konteksty.
Implementacja IsBusy
Nie uwidaczniaj
IsBusywłaściwości, jeśli klasa obsługuje wiele współbieżnych wywołań. Na przykład pełnomocnicy usług sieci Web XML nie ujawniają właściwościIsBusy, ponieważ umożliwiają wiele równoczesnych wywołań metod asynchronicznych.Właściwość powinna zwracać
IsBusytruepo wywołaniu metody MethodNameAsync i przed wywołaniem zdarzenia MethodNameCompleted. W przeciwnym razie powinien zwrócić wartośćfalse. Składniki BackgroundWorker i WebClient to przykłady klas, które uwidaczniająIsBusywłaściwość.
Anulowanie
Jeśli to możliwe, wspieraj anulowanie. To umożliwia deweloperom zapewnienie lepszego doświadczenia użytkownika aplikacji przy użyciu klasy.
W przypadku anulowania ustaw flagę Cancelled w obiekcie AsyncCompletedEventArgs.
Upewnij się, że każda próba uzyskania dostępu do wyniku zgłasza informację InvalidOperationException o anulowaniu operacji. AsyncCompletedEventArgs.RaiseExceptionIfNecessary Użyj metody , aby przeprowadzić tę weryfikację.
Ustaw, aby wywołania metody anulowania zawsze kończyły się pomyślnie i nigdy nie zgłaszały wyjątku. Ogólnie rzecz biorąc, klient nie jest powiadamiany, czy operacja jest w danym momencie rzeczywiście anulowalna, ani czy wcześniej wystawione anulowanie odniosło sukces. Jednak aplikacja będzie zawsze otrzymywać powiadomienie po pomyślnym anulowaniu, ponieważ aplikacja bierze udział w procesie ukończenia.
Zgłoś zdarzenie MethodNameCompleted po anulowaniu operacji.
Błędy i wyjątki
- Przechwyć wszelkie wyjątki występujące w operacji asynchronicznej i przypisz wartość AsyncCompletedEventArgs.Error właściwości temu wyjątkowi.
Wątkowanie i konteksty
Dla prawidłowego działania Twojej klasy kluczowe jest, aby procedury obsługi zdarzeń klienta były wywoływane we właściwym wątku lub kontekście dla określonego modelu aplikacji, w tym aplikacji ASP.NET i Windows Forms. Dostępne są dwie ważne klasy pomocnicze, aby upewnić się, że klasa asynchroniczna działa prawidłowo w dowolnym modelu aplikacji: AsyncOperation i AsyncOperationManager.
AsyncOperationManager udostępnia jedną metodę , CreateOperationktóra zwraca wartość AsyncOperation. Metoda MethodNameAsync wywołuje CreateOperation, a klasa używa zwróconego AsyncOperation do śledzenia okresu istnienia zadania asynchronicznego.
Aby zgłosić postęp, wyniki przyrostowe i ukończenie do klienta, wywołaj metody Post i OperationCompleted na obiekcie AsyncOperation. AsyncOperation odpowiada za obsługę wywołań procedur obsługi zdarzeń klienta, kierując je do odpowiedniego wątku lub kontekstu.
Uwaga / Notatka
Te reguły można obejść, jeśli jawnie chcesz sprzeciwić się zasadom modelu aplikacji, ale nadal korzystać z innych zalet stosowania wzorca asynchronicznego opartego na zdarzeniach. Na przykład możesz chcieć, aby klasa działająca w Windows Forms była wolnowątkowa. Możesz utworzyć bezpłatną klasę wątkową, o ile deweloperzy rozumieją dorozumiane ograniczenia. Aplikacje konsolowe nie synchronizują wykonywania wywołań Post . Może to spowodować, że ProgressChanged zdarzenia są wywoływane poza kolejnością. Aby mieć sekwencyjne wykonywanie wywołań Post, zaimplementuj i zainstaluj klasę System.Threading.SynchronizationContext.
Aby uzyskać więcej informacji na temat używania AsyncOperation i AsyncOperationManager do włączania operacji asynchronicznych, zobacz „Instrukcje: implementowanie składnika obsługującego asynchroniczny wzorzec oparty na zdarzeniach”.
Wytyczne
W idealnym przypadku każde wywołanie metody powinno być niezależne od pozostałych. Należy unikać sprzęgania wywołań z udostępnionymi zasobami. Jeśli zasoby mają być współużytkowane przez wywołania, należy zapewnić odpowiedni mechanizm synchronizacji w implementacji.
Nie zaleca się projektowania, które wymagają od klienta implementacji synchronizacji. Na przykład można mieć metodę asynchroniczną, która odbiera globalny obiekt statyczny jako parametr; wiele współbieżnych wywołań takiej metody może spowodować uszkodzenie danych lub zakleszczenia.
Jeśli zaimplementujesz metodę z przeciążeniem wielu wywołań (
userStatew podpisie), klasa będzie musiała zarządzać kolekcją stanów użytkownika lub identyfikatorami zadań oraz odpowiadającymi im oczekującymi operacjami. Ta kolekcja powinna być chroniona przy użyciulockregionów, ponieważ różne wywołania dodają i usuwająuserStateobiekty w kolekcji.Rozważ ponowne użycie
CompletedEventArgsklas tam, gdzie jest to możliwe i odpowiednie. W takim przypadku nazewnictwo nie jest zgodne z nazwą metody, ponieważ dany delegat i EventArgs typ nie są powiązane z jedną metodą. Jednak zmuszanie programistów do rzutowania wartości uzyskanej z właściwości na obiekcie EventArgs nigdy nie jest akceptowalne.Jeśli tworzysz klasę pochodną z Component klasy, nie implementuj i nie instaluj swojej własnej klasy SynchronizationContext. Modele aplikacji, a nie składniki, kontrolują używane SynchronizationContext.
Przy użyciu programowania wielowątkowego wszelkiego rodzaju potencjalnie narażasz się na bardzo poważne i złożone błędy. Przed zaimplementowaniem dowolnego rozwiązania korzystającego z wielowątkowości zobacz Managed Threading Best Practices (Najlepsze praktyki dotyczące zarządzania wątkami).
Zobacz także
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implementowanie wzorca asynchronicznego opartego na zdarzeniach
- Asynchroniczny wzorzec oparty na zdarzeniach (EAP)
- Podejmowanie decyzji o tym, kiedy należy zaimplementować wzorzec asynchroniczny oparty na zdarzeniach
- Najlepsze rozwiązania dotyczące implementowania wzorca asynchronicznego opartego na zdarzeniach
- Instrukcje: używanie składników obsługujących wzorzec asynchroniczny oparty na zdarzeniach
- Instrukcje: implementowanie składnika obsługującego wzorzec asynchroniczny oparty na zdarzeniach