Devo usar a lista ou simplesmente acionar para acompanhar os assinantes de um IOBServable?
-
25-09-2019 - |
Pergunta
Estou implementando o IObservable<T>
Interface em algumas classes. eu usei Refletor Para descobrir como isso é normalmente feito em Rx. Sobre como um observável acompanha seus assinantes e os notifica através de seus OnNext
Método, tropecei em código semelhante a este:
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);
}
Como todos os delegados são multicast-cast, isso não poderia ser simplificado para:
Action<T> observers;
// subscribe observer:
public IDisposable Subscribe(IObserver<T> observer)
{
observers += observer.OnNext;
...
}
// trigger observers' OnNext:
...
observers(value);
Ou existem vantagens específicas para a primeira abordagem (desempenho de desempenho, encadeamento/concorrência,…)?
Solução
Em geral, chamar os delegados individualmente fornece mais controle sobre o comportamento:
- Se um delegado aumentar uma exceção, você poderá continuar ligando para os outros, por exemplo, ou remover o delegado com falha da sua lista.
- Se você quiser ligar para os delegados em paralelo, é realmente fácil.
- Se você precisar ligar para eles em um determinado pedido, poderá garantir facilmente o pedido correto (não tenho certeza de que o pedido de chamadas de delegados multicast seja definido).
Outras dicas
Normalmente você não implementa IObservable<T>
você mesmo, você devolve um IObservable<T>
de um método usando um dos métodos de geração (como Observable.Create
).
No entanto, se você for implementar a interface, você deve embrulhar um interno Subject<T>
que lidará com todos os problemas de simultaneidade para você:
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 você decidir ficar com o delegado (por qualquer motivo), pelo menos verifique se você está cancelando inscrição em seu IDisposable
valor de retorno:
observers += observer.OnNext;
return Disposable.Create(() => observers -= observer.OnNext);