Procedure consigliate per un modello di progettazione observerObserver Design Pattern Best Practices

In.NET Framework, il modello di progettazione osservatore è implementato come un insieme di interfacce.In the .NET Framework, the observer design pattern is implemented as a set of interfaces. L'interfaccia System.IObservable<T> rappresenta il provider di dati, che è anche responsabile di fornire un'implementazione di IDisposable che consenta agli osservatori di annullare la sottoscrizione di notifiche.The System.IObservable<T> interface represents the data provider, which is also responsible for providing an IDisposable implementation that lets observers unsubscribe from notifications. L'interfaccia System.IObserver<T> rappresenta l'osservatore.The System.IObserver<T> interface represents the observer. In questo argomento vengono descritte le procedure consigliate che gli sviluppatori devono seguire per implementare il modello di progettazione osservatore usando queste interfacce.This topic describes the best practices that developers should follow when implementing the observer design pattern using these interfaces.

ThreadingThreading

In genere, un provider implementa il metodo IObservable<T>.Subscribe aggiungendo un osservatore specifico a un elenco di server di sottoscrizione, che è rappresentato da un oggetto di raccolta, e implementa il metodo IDisposable.Dispose rimuovendo un osservatore specifico dall'elenco dei server di sottoscrizione.Typically, a provider implements the IObservable<T>.Subscribe method by adding a particular observer to a subscriber list that is represented by some collection object, and it implements the IDisposable.Dispose method by removing a particular observer from the subscriber list. Un osservatore può chiamare questi metodi in qualsiasi momento.An observer can call these methods at any time. Inoltre, perché il contratto provider/osservatore non specifica chi è responsabile dell'annullamento della sottoscrizione dopo il metodo di callback IObserver<T>.OnCompleted, il provider e l'osservatore possono provare a rimuovere lo stesso membro dall'elenco.In addition, because the provider/observer contract does not specify who is responsible for unsubscribing after the IObserver<T>.OnCompleted callback method, the provider and observer may both try to remove the same member from the list. Grazie a questa possibilità, entrambi i metodi Subscribe e Dispose dovrebbero essere thread-safe.Because of this possibility, both the Subscribe and Dispose methods should be thread-safe. In genere, ciò comporta l'uso di una raccolta simultanea o di un blocco.Typically, this involves using a concurrent collection or a lock. Le implementazioni che non sono thread-safe devono documentare esplicitamente che non lo sono.Implementations that are not thread-safe should explicitly document that they are not.

Tutte le garanzie aggiuntive devono essere specificate in un livello all'inizio del contratto provider/osservatore.Any additional guarantees have to be specified in a layer on top of the provider/observer contract. Gli implementatori devono indicare chiaramente quando impongono requisiti aggiuntivi per evitare confusione sul contratto di osservatore.Implementers should clearly call out when they impose additional requirements to avoid user confusion about the observer contract.

Gestione delle eccezioniHandling Exceptions

A causa dell'accoppiamento debole tra un provider di dati e un osservatore, le eccezioni nel modello di progettazione osservatore sono esclusivamente informative.Because of the loose coupling between a data provider and an observer, exceptions in the observer design pattern are intended to be informational. Ciò influisce sul modo in cui provider e osservatori gestiscono le eccezioni nel modello di progettazione osservatore.This affects how providers and observers handle exceptions in the observer design pattern.

Provider: Chiamata al metodo OnErrorThe Provider -- Calling the OnError Method

Il metodo OnError è concepito come un messaggio informativo agli osservatori, in modo analogo al metodo IObserver<T>.OnNext.The OnError method is intended as an informational message to observers, much like the IObserver<T>.OnNext method. Tuttavia, il metodo OnNext è progettato al fine di fornire a un osservare dati correnti o aggiornati, laddove il metodo OnError è progettato per indicare che il provider non può fornire dati validi.However, the OnNext method is designed to provide an observer with current or updated data, whereas the OnError method is designed to indicate that the provider is unable to provide valid data.

Il provider dovrebbe seguire queste procedure consigliate durante la gestione delle eccezioni e la chiamata del metodo OnError:The provider should follow these best practices when handling exceptions and calling the OnError method:

  • Il provider deve gestire le proprie eccezioni in caso di requisiti specifici.The provider must handle its own exceptions if it has any specific requirements.

  • Il provider non dovrebbe aspettarsi o richiedere che gli osservatori gestiscano le eccezioni in alcun modo particolare.The provider should not expect or require that observers handle exceptions in any particular way.

  • Il provider dovrà chiamare il metodo OnError quando gestisce un'eccezione che compromette la sua capacità di fornire aggiornamenti.The provider should call the OnError method when it handles an exception that compromises its ability to provide updates. Le informazioni su tali eccezioni possono essere passate all'osservatore.Information on such exceptions can be passed to the observer. In altri casi, non è necessario notificare un'eccezione agli osservatori.In other cases, there is no need to notify observers of an exception.

Quando il provider chiama il metodo OnError o IObserver<T>.OnCompleted, non vi saranno altre notifiche e il provider potrà annullare la sottoscrizione dei relativi osservatori.Once the provider calls the OnError or IObserver<T>.OnCompleted method, there should be no further notifications, and the provider can unsubscribe its observers. Questi ultimi, tuttavia, potranno a loro volta annullare una sottoscrizione in qualsiasi momento, sia prima sia dopo aver ricevuto una notifica OnError o IObserver<T>.OnCompleted.However, the observers can also unsubscribe themselves at any time, including both before and after they receive an OnError or IObserver<T>.OnCompleted notification. Il modello di progettazione dell'osservatore non indica se il provider o l'osservatore è responsabile dell'annullamento della sottoscrizione. Quindi, è possibile che entrambi provino ad annullare la sottoscrizione.The observer design pattern does not dictate whether the provider or the observer is responsible for unsubscribing; therefore, there is a possibility that both may attempt to unsubscribe. In genere, quando gli osservatori annullano l'iscrizione, vengono rimossi da una raccolta di sottoscrittori.Typically, when observers unsubscribe, they are removed from a subscribers collection. In un'applicazione a thread singolo, l'implementazione di IDisposable.Dispose dovrà garantire che un riferimento all'oggetto sia valido e che l'oggetto sia un membro della raccolta di sottoscrittori prima di provare a rimuoverlo.In a single-threaded application, the IDisposable.Dispose implementation should ensure that an object reference is valid and that the object is a member of the subscribers collection before attempting to remove it. In un'applicazione multithreading, è necessario usare un oggetto di raccolta thread-safe, come ad esempio un oggetto System.Collections.Concurrent.BlockingCollection<T>.In a multithreaded application, a thread-safe collection object, such as a System.Collections.Concurrent.BlockingCollection<T> object, should be used.

Osservatore: implementazione del metodo OnErrorThe Observer -- Implementing the OnError Method

Quando un osservatore riceve una notifica di errore da un provider, l'osservatore deve considerare l'eccezione come informativa e non deve eseguire alcuna operazione particolare.When an observer receives an error notification from a provider, the observer should treat the exception as informational and should not be required to take any particular action.

L'osservatore dovrebbe seguire queste procedure consigliate durante la risposta a gestione delle eccezioni e la chiamata al metodo OnError da un provider:The observer should follow these best practices when responding to an OnError method call from a provider:

  • L'osservatore non deve generare eccezioni dalle implementazioni dell'interfaccia, come ad esempio OnNext o OnError.The observer should not throw exceptions from its interface implementations, such as OnNext or OnError. Tuttavia, se l'osservatore genera eccezioni, deve aspettarsi che queste eccezioni rimangano non gestite.However, if the observer does throw exceptions, it should expect these exceptions to go unhandled.

  • Per preservare lo stack di chiamate, un osservatore che intenda generare un oggetto Exception che è stato passato al relativo metodo OnError dovrà eseguire il wrapping dell'eccezione prima di generarla.To preserve the call stack, an observer that wishes to throw an Exception object that was passed to its OnError method should wrap the exception before throwing it. A questo scopo è necessario usare un oggetto eccezione standard.A standard exception object should be used for this purpose.

Procedure consigliate aggiuntiveAdditional Best Practices

Un tentativo di annullamento della registrazione nel metodo IObservable<T>.Subscribe può produrre un riferimento null.Attempting to unregister in the IObservable<T>.Subscribe method may result in a null reference. È quindi consigliabile evitare questa operazione.Therefore, we recommend that you avoid this practice.

Nonostante sia possibile associare un osservatore a più provider, il modello consigliato consiste nell'associare un'istanza di IObserver<T> a una sola istanza di IObservable<T>.Although it is possible to attach an observer to multiple providers, the recommended pattern is to attach an IObserver<T> instance to only one IObservable<T> instance.

Vedere ancheSee Also

Modello di progettazione observerObserver Design Pattern
Procedura: Implementare un elemento ObserverHow to: Implement an Observer
Procedura: Implementare un providerHow to: Implement a Provider