Notatka
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.
Na platformie .NET wzorzec projektowy obserwatora jest implementowany jako zestaw interfejsów. Interfejs System.IObservable<T> reprezentuje dostawcę danych, który jest również odpowiedzialny za zapewnienie IDisposable implementacji, która umożliwia obserwatorom anulowanie subskrypcji powiadomień. Interfejs System.IObserver<T> reprezentuje obserwatora.
W tym artykule opisano najlepsze rozwiązania, które należy zastosować podczas implementowania wzorca projektowego obserwatora za pomocą tych interfejsów.
Rozważ alternatywy przed wdrożeniem
Interfejsy IObservable<T> i IObserver<T> są odpowiednie dla scenariuszy powiadomień opartych na wypychaniach, ale inne wzorce .NET mogą być lepiej dopasowane. Aby uzyskać proste powiadomienie w ramach jednej aplikacji, użyj zdarzeń. W przypadku asynchronicznych sekwencji typu pull, w których konsument kontroluje tempo, użyj IAsyncEnumerable<T>. W przypadku wzorca producent–konsument z mechanizmem kontroli ciśnienia zwrotnego użyj System.Threading.Channels. W przypadku złożonego tworzenia, filtrowania i przekształcania zdarzeń należy użyć pakietu System.Reactive (Rx.NET) zamiast implementować bezpośrednio IObservable<T>. Aby uzyskać więcej informacji, zobacz Wzorzec projektowania obserwatora.
Używanie oddzielnego typu dla danych powiadomień
Obiekt zawierający dane, które dostawca wysyła swoim obserwatorom, odpowiada parametrowi typu generycznego elementów IObservable<T> i IObserver<T>. Chociaż ten obiekt może być taki sam jak implementacja IObservable<T> , zdefiniuj go jako oddzielny typ. Dedykowany typ danych zachowuje obowiązki dostawcy niezależnie od ładunku powiadomień i ułatwia rozwijanie interfejsu API.
Nie należy polegać na kolejności powiadomień
Kolejność odbierania powiadomień przez obserwatorów nie jest zdefiniowana. Dostawca może użyć dowolnej metody w celu określenia kolejności, więc nie zapisuj obserwatorów, którzy zależą od powiadamiania przed lub po innym obserwatorze.
Zapewnij, aby Subscribe i Dispose były bezpieczne dla wątków
Zazwyczaj dostawca implementuje IObservable<T>.Subscribe metodę przez dodanie obserwatora do listy subskrybentów reprezentowanej przez obiekt kolekcji i implementuje IDisposable.Dispose metodę przez usunięcie obserwatora z tej listy. Obserwator może wywołać te metody w dowolnym momencie. Umowa dostawcy/obserwatora nie określa, kto jest odpowiedzialny za anulowanie subskrypcji po IObserver<T>.OnCompleted metodzie wywołania zwrotnego, więc dostawca i obserwator mogą próbować usunąć tego samego członka z listy.
Aby uniknąć warunków wyścigu, zarówno metody, jak Subscribe i Dispose są bezpieczne wątkowo. Zazwyczaj wiąże się to z użyciem kolekcji współbieżnej lub blokady. Implementacje, które nie są bezpieczne wątkowo, powinny jawnie udokumentować, że nie są.
Dokumentowanie wszelkich dodatkowych gwarancji kontraktowych
Określ wszelkie dodatkowe gwarancje w warstwie nad kontraktem dostawca/obserwator. Jeśli nakładasz dodatkowe wymagania, wyraźnie to zaznacz, aby użytkownicy nie byli zdezorientowani co do kontraktu obserwatora.
Traktuj wyjątki jako informacje
Ze względu na luźne sprzężenie między dostawcą danych a obserwatorem wyjątki we wzorcu projektowania obserwatora mają być informacyjne. Ta cecha wpływa na sposób obsługi wyjątków przez dostawców i obserwatorów.
Wywołaj funkcję OnError tylko wtedy, gdy aktualizacje nie mogą kontynuować
Metoda OnError jest przeznaczona jako komunikat informacyjny dla obserwatorów, podobnie jak IObserver<T>.OnNext metoda. OnNext Jednak metoda zapewnia obserwatorowi bieżące lub zaktualizowane dane, natomiast OnError metoda wskazuje, że dostawca nie może dostarczyć prawidłowych danych.
Postępuj zgodnie z poniższymi najlepszymi rozwiązaniami podczas obsługi wyjątków i wywoływania OnError metody:
- Dostawca musi obsługiwać własne wyjątki, jeśli ma określone wymagania.
- Dostawca nie powinien oczekiwać ani wymagać, aby obserwatorzy obsługiwali wyjątki w żaden konkretny sposób.
- Dostawca powinien wywołać metodę OnError , gdy obsługuje wyjątek, który narusza jego zdolność do dostarczania aktualizacji. Przekazywanie informacji o takich wyjątkach do obserwatora. W innych przypadkach nie ma potrzeby powiadamiania obserwatorów o wyjątku.
Po wywołaniu przez dostawcę metody OnError lub IObserver<T>.OnCompleted nie powinno już być żadnych dalszych powiadomień, a dostawca może wyrejestrować swoich obserwatorów. Obserwatorzy mogą jednak w dowolnym momencie anulować subskrypcję, w tym przed i po otrzymaniu powiadomieniaOnError.IObserver<T>.OnCompleted Wzorzec projektu obserwatora nie określa, czy dostawca lub obserwator jest odpowiedzialny za anulowanie subskrypcji, więc obaj mogą próbować anulować subskrypcję. Zazwyczaj, gdy obserwatorzy wypisują się z subskrypcji, są usuwani z kolekcji subskrybentów. W aplikacji jednowątkowej implementacja IDisposable.Dispose powinna upewnić się, że odwołanie do obiektu jest prawidłowe i że obiekt jest członkiem kolekcji subskrybentów przed podjęciem próby usunięcia obiektu. W aplikacji wielowątkowej użyj blokady, aby chronić kolekcję obserwatorów.
Uznawaj powiadomienia OnError za informacyjne w obserwatorach
Gdy obserwator otrzymuje powiadomienie o błędzie od dostawcy, obserwator powinien traktować wyjątek jako informacyjny i nie powinien być wymagany do podjęcia żadnej konkretnej akcji.
Postępuj zgodnie z tymi najlepszymi praktykami, gdy odpowiadasz na wywołanie metody OnError od dostawcy:
- Nie zgłaszaj wyjątków z implementacji interfejsu, takich jak OnNext lub OnError. Jeśli obserwator zgłasza wyjątki, należy oczekiwać, że te wyjątki nie będą obsługiwane.
- Aby zachować stos wywołań, obserwator, który chce zgłosić obiekt Exception przekazany do swojej metody OnError, powinien opakować wyjątek przed jego ponownym zgłoszeniem. W tym celu należy użyć standardowego obiektu wyjątku.
Nie wyrejestrowuj w metodzie subskrybowania
Nie próbuj wyrejestrowywać w metodzie IObservable<T>.Subscribe, ponieważ może to spowodować puste odwołanie.
Dołączanie obserwatora do jednego dostawcy
Chociaż obserwatora można przypisać do wielu dostawców, zaleca się przypisywanie jednego wystąpienia IObserver<T> tylko do jednego wystąpienia IObservable<T>.