Dovrei usare List o semplicemente Azione per tenere traccia degli abbonati di un IObservable?
-
25-09-2019 - |
Domanda
sto implementando l'interfaccia IObservable<T>
in alcune classi. Ho usato Reflector di capire come questo è in genere fatto in Rx . Per quanto riguarda il modo un'osservabile registra i suoi abbonati e li avvisa tramite il loro metodo OnNext
, sono incappato in codice simile a questo:
private List<Observer<T>> observers;
// subscribe a new observer:
public IDisposable Subscribe(IObserver<T> observer)
{
observers.Add(observer);
...
}
// trigger all observers' OnNext method:
...
foreach (IObserver<T> observer in observers)
{
observer.OnNext(value);
}
Dal momento che tutti i delegati sono multi-cast, non potrebbe questo essere semplificata in:
Action<T> observers;
// subscribe observer:
public IDisposable Subscribe(IObserver<T> observer)
{
observers += observer.OnNext;
...
}
// trigger observers' OnNext:
...
observers(value);
O ci sono vantaggi specifici per il primo approccio (prestazioni, problemi di threading / concorrenza, ...)?
Soluzione
In generale, chiamando i delegati vi dà individualmente maggiore controllo sul comportamento:
- Se un delegato solleva un'eccezione è possibile mantenere chiamando gli altri, per esempio, o rimuovere il delegato in errore dalla vostra lista.
- Se si desidera chiamare i delegati in parallelo, è davvero facile.
- Se avete bisogno di chiamarli in un certo ordine, si può facilmente garantire l'ordine corretto (non sono sicuro che l'ordine delle chiamate delegato multicast è definito).
Altri suggerimenti
Di solito non implementare IObservable<T>
voi stessi, restituire un IObservable<T>
da un metodo utilizzando uno dei metodi di generazione (come Observable.Create
).
Tuttavia, se avete intenzione di implementare l'interfaccia da soli, si dovrebbe avvolgere un Subject<T>
interna che gestirà tutti i problemi di concorrenza per voi:
public class CustomObservable<T> : IObservable<T>
{
private Subject<T> subject = new Subject<T>();
public IDisposable Subscribe(IObserver<T> observer)
{
return subject.Subscribe(observer);
}
private void EmitValue(T value)
{
subject.OnNext(value);
}
}
NB: Se si decide di attaccare con il delegato (per qualsiasi motivo), almeno assicurarsi che si sta annullamento dell'iscrizione nel valore di ritorno IDisposable
:
observers += observer.OnNext;
return Disposable.Create(() => observers -= observer.OnNext);