Aanbevolen procedures voor het ontwerppatroon waarnemer

In .NET wordt het ontwerppatroon van de waarnemer geïmplementeerd als een set interfaces. De System.IObservable<T> interface vertegenwoordigt de gegevensprovider, die ook verantwoordelijk is voor het bieden van een IDisposable implementatie waarmee waarnemers zich kunnen afmelden voor meldingen. De System.IObserver<T> interface vertegenwoordigt de waarnemer.

In dit artikel worden aanbevolen procedures beschreven die u moet volgen wanneer u het ontwerppatroon van de waarnemer implementeert met deze interfaces.

Alternatieven overwegen voordat u implementeert

De interfaces IObservable<T> en IObserver<T> zijn geschikt voor pushgebaseerde meldingsscenario's, maar andere .NET patronen zijn mogelijk beter geschikt. Gebruik gebeurtenissen voor eenvoudige meldingen binnen één toepassing. Voor asynchrone op pull gebaseerde reeksen waarbij de consument het tempo bepaalt, gebruikt u IAsyncEnumerable<T>. Gebruik System.Threading.Channels voor producenten-consumentenpatronen met backpressure. Voor complexe gebeurtenissamenstelling, filtering en transformatie gebruikt u het pakket System.Reactive (Rx.NET) in plaats van rechtstreeks IObservable<T> te implementeren. Zie het Observer-ontwerppatroon voor meer informatie.

Een afzonderlijk type gebruiken voor meldingsgegevens

Het object dat de gegevens bevat die de provider naar de waarnemers verzendt, komt overeen met de algemene typeparameter van IObservable<T> en IObserver<T>. Hoewel dit object hetzelfde kan zijn als de IObservable<T> implementatie, definieert u het als een afzonderlijk type. Een specifiek gegevenstype houdt de verantwoordelijkheden van de provider gescheiden van de nettolading van de melding en maakt de API eenvoudiger te ontwikkelen.

Vertrouw niet op meldingsorder

De volgorde waarin waarnemers meldingen ontvangen, is niet gedefinieerd. De provider mag elke willekeurige methode gebruiken om de volgorde te bepalen, dus schrijf geen observers die ervan afhankelijk zijn dat ze vóór of na een andere observer op de hoogte worden gebracht.

Abonneren en thread-veilig verwijderen

Normaal gesproken implementeert een provider de IObservable<T>.Subscribe methode door een waarnemer toe te voegen aan een abonneelijst die wordt vertegenwoordigd door een verzamelingsobject en wordt de IDisposable.Dispose methode geïmplementeerd door de waarnemer uit die lijst te verwijderen. Een waarnemer kan deze methoden op elk gewenst moment aanroepen. Het contract tussen provider en waarnemer specificeert niet wie verantwoordelijk is voor het afmelden na de IObserver<T>.OnCompleted callback-methode, waardoor de provider en waarnemer mogelijk allebei proberen hetzelfde lid uit de lijst te verwijderen.

Om racecondities te voorkomen, moet u zowel de methoden Subscribe en Dispose thread-safe maken. Dit omvat doorgaans het gebruik van een gelijktijdige verzameling of een vergrendeling. Implementaties die niet thread-safe zijn, moeten expliciet documenteren dat ze niet zijn.

Documenteer eventuele extra contractgaranties

Geef eventuele extra garanties op in een laag boven op het provider-/waarnemerscontract. Wanneer u andere vereisten oplegt, moet u ze duidelijk aanroepen, zodat gebruikers niet in de war raken over het waarnemerscontract.

Uitzonderingen verwerken als informatie

Vanwege de losse koppeling tussen een gegevensprovider en een waarnemer zijn uitzonderingen in het ontwerppatroon van de waarnemer bedoeld om informatief te zijn. Dit kenmerk is van invloed op de manier waarop providers en waarnemers uitzonderingen verwerken.

OnError alleen aanroepen wanneer updates niet kunnen worden voortgezet

De OnError methode is bedoeld als een informatief bericht voor waarnemers, net als de IObserver<T>.OnNext methode. De OnNext methode biedt echter een waarnemer met actuele of bijgewerkte gegevens, terwijl de OnError methode aangeeft dat de provider geen geldige gegevens kan leveren.

Volg deze aanbevolen procedures wanneer u uitzonderingen afhandelt en de OnError methode aanroept:

  • De provider moet zijn eigen uitzonderingen afhandelen als deze specifieke vereisten heeft.
  • De provider mag niet verwachten of vereisen dat waarnemers uitzonderingen op een bepaalde manier verwerken.
  • De provider moet de OnError methode aanroepen wanneer deze een uitzondering afhandelt die de mogelijkheid om updates te bieden in gevaar komt. Geef informatie over dergelijke uitzonderingen door aan de waarnemer. In andere gevallen is het niet nodig om waarnemers op de hoogte te stellen van een uitzondering.

Nadat de provider de OnError of IObserver<T>.OnCompleted methode heeft aangeroepen, mogen er geen verdere meldingen meer zijn en kan de provider de waarnemers afmelden. De waarnemers kunnen zich echter ook op elk moment afmelden, zowel vóór als ná het ontvangen van een OnError- of IObserver<T>.OnCompleted-melding. Het ontwerppatroon van de waarnemer bepaalt niet of de provider of de waarnemer verantwoordelijk is voor het afmelden, dus beide kunnen proberen zich af te melden. Wanneer waarnemers zich afmelden, worden ze meestal verwijderd uit een abonneesverzameling. In een toepassing met één thread moet de IDisposable.Dispose implementatie ervoor zorgen dat een objectverwijzing geldig is en of het object lid is van de verzameling abonnees voordat het object wordt verwijderd. Gebruik in een multithreaded-toepassing een vergrendeling om de verzameling waarnemers te beschermen.

OnError-meldingen als informatief beschouwen in observers

Wanneer een waarnemer een foutmelding van een provider ontvangt, moet de waarnemer de uitzondering behandelen als informatief en mag deze geen specifieke actie ondernemen.

Volg deze aanbevolen procedures wanneer u reageert op een OnError methodeaanroep van een provider:

  • Gooi geen uitzonderingen op interface-implementaties zoals OnNext of OnError. Als de observer toch uitzonderingen opwerpt, moet u ervan uitgaan dat deze uitzonderingen niet worden afgehandeld.
  • Om de aanroepstack te behouden, moet een observer die een Exception-object wil werpen dat aan de methode OnError is doorgegeven, de uitzondering verpakken voordat deze wordt geworpen. Gebruik hiervoor een standaard uitzonderingsobject.

Registratie bij de methode Subscribe niet ongedaan maken

Probeer de registratie van de IObservable<T>.Subscribe methode niet ongedaan te maken, omdat dit kan resulteren in een null-verwijzing.

Een waarnemer koppelen aan één provider

Hoewel u een waarnemer aan meerdere providers kunt koppelen, is het aanbevolen patroon om een IObserver<T> exemplaar aan slechts één IObservable<T> exemplaar te koppelen.