2010-10-23 18 views
3

J'implémente l'interface IObservable<T> sur certaines classes. J'ai utilisé Reflector pour comprendre comment cela se fait typiquement dans Rx. En ce qui concerne la façon dont une observable garde la trace de ses abonnés et les notifie par leur méthode OnNext, je suis tombé sur un code similaire à ceci:Devrais-je utiliser la liste <IObserver> ou simplement l'action <T> pour garder une trace des abonnés d'un IObservable?

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); 
} 

Comme tous les délégués sont multi-acteurs, pourrait pas être simplifiée:

Action<T> observers; 

// subscribe observer: 
public IDisposable Subscribe(IObserver<T> observer) 
{ 
    observers += observer.OnNext; 
    ... 
} 

// trigger observers' OnNext: 
... 
observers(value); 

Ou y at-il des avantages spécifiques à la première approche (performance, problèmes filetage/accès concurrentiel, & hellip;)?

Répondre

5

En général, appelant les délégués individuellement, vous donne plus de contrôle sur le comportement:

  • Si un délégué soulève une exception, vous pouvez continuer à appeler les autres, par exemple, ou supprimer le délégué faillée de votre liste.
  • Si vous voulez appeler les délégués en parallèle, c'est vraiment facile.
  • Si vous devez les appeler dans un certain ordre, vous pouvez facilement garantir l'ordre correct (je ne suis pas sûr que l'ordre des appels de délégués de multidiffusion est défini).
+0

de plus, vous aussi rencontrer des problèmes avec les doublons si vous avez utilisé l'application délégué multicast gardon. Si deux observateurs ayant exactement les mêmes méthodes OnNext ont été ajoutés, et qu'un a ensuite été supprimé, cela supprimerait le rappel pour les deux. – SoftMemes

+0

Libéré: Non, ce n'est pas un problème. Seule la première instance d'un délégué donné est supprimée. – Gabe

+0

Vous avez raison. Ce qui arrivera cependant, c'est que le «mauvais» délégué sera supprimé, ce qui modifiera l'ordre de notification des observateurs (qui peut ou non être pertinent). – SoftMemes

4

En général, vous ne vous, vous revenez IObservable<T> implémentent pas d'IObservable<T> d'une méthode en utilisant l'une des méthodes de génération (comme Observable.Create).

Cependant, si vous allez implémenter l'interface vous-même, vous devez envelopper un Subject<T> interne qui traitera toutes les questions de concurrence pour vous:

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: Si vous décidez de rester à la délégué (pour une raison quelconque), au moins vous assurer que vous le désabonnement dans votre IDisposable valeur de retour:

observers += observer.OnNext; 
return Disposable.Create(() => observers -= observer.OnNext); 
+0

merci de répondre.Notez cependant que ma bibliothèque n'est pas basée sur Rx, je ne compte que sur les deux interfaces du .NET 4.0 BCL. J'ai seulement vérifié avec l'implémentation Rx pour voir comment cela se fait habituellement. – stakx

+2

Oui, c'est un excellent conseil! Pensez à implémenter IObservable directement comme commun à implémenter IEnumerable; En général, vous essayez d'utiliser l'une des implémentations IObservable déjà construites, comme le Sujet