Il existe des interfaces IObservable et IObserver dans .NET (également ici et ici ). Fait intéressant, l'implémentation concrète de l'IObserver ne contient pas de référence directe à l'IObservable. Il ne sait pas à qui il est abonné. Il ne peut invoquer que l'abonné. "Veuillez retirer l'épingle pour vous désinscrire."
edit: le désabonné implémente le IDisposable
. Je pense que ce schéma a été utilisé pour éviter le problème de l'auditeur périmé .
Cependant, deux choses ne sont pas tout à fait claires pour moi.
- La classe Unsubscriber interne fournit-elle le comportement d'abonnement et d'oubli? Qui (et quand exactement) fait appel
IDisposable.Dispose()
au désabonné? Le garbage collector (GC) n'est pas déterministe.
[Avertissement: dans l'ensemble, j'ai passé plus de temps avec C et C ++ qu'avec C #.] Que se passe-t-il si je veux abonner un observateur K à un L1 observable et que l'observateur est déjà abonné à un autre L2 observable?
K.Subscribe(L1); K.Subscribe(L2); K.Unsubscribe(); L1.PublishObservation(1003); L2.PublishObservation(1004);
Lorsque j'ai exécuté ce code de test contre l'exemple de MSDN, l'observateur est resté abonné à L1. Ce serait particulier dans le développement réel. Potentiellement, il existe 3 pistes pour améliorer cela:
- Si l'observateur a déjà une instance de désabonnement (c'est-à-dire qu'elle est déjà abonnée), il se désabonne discrètement du fournisseur d'origine avant de s'abonner à une nouvelle. Cette approche masque le fait qu'il n'est plus abonné au fournisseur d'origine, ce qui peut devenir une surprise plus tard.
- Si l'observateur possède déjà une instance de désabonnement, alors lève une exception. Un code d'appel qui se comporte bien doit désinscrire explicitement l'observateur.
- Observer est abonné à plusieurs fournisseurs. C'est l'option la plus intrigante, mais peut-elle être mise en œuvre avec IObservable et IObserver? Voyons voir. Il est possible pour l'observateur de conserver une liste des objets non abonnés: un pour chaque source. Malheureusement,
IObserver.OnComplete()
ne fournit pas de référence au fournisseur qui l'a envoyé. Ainsi, l'implémentation IObserver avec plusieurs fournisseurs ne serait pas en mesure de déterminer lequel désinscrire.
Le serveur IObserver de .NET était-il destiné à s'abonner à plusieurs serveurs IObservables?
La définition classique du modèle d'observateur exige-t-elle qu'un seul observateur doit être en mesure de s'abonner à plusieurs fournisseurs? Ou est-elle facultative et dépendante de la mise en œuvre?
la source
using
bloc. Le coût d'une déclaration d'abonnement doit être pratiquement nul, vous devez donc compenser le bloc using, vous abonner, laisser le bloc using (donc vous désinscrire), ce qui rend le code plutôt inutileTu as raison. L'exemple fonctionne mal pour plusieurs IObservables.
Je suppose que OnComplete () ne fournit pas de référence car ils ne veulent pas que IObservable doive le garder. Si j'écrivais que je prendrais probablement en charge plusieurs abonnements en demandant à Subscribe de prendre un identifiant comme deuxième paramètre, qui est renvoyé à l'appel OnComplete (). Vous pourriez donc dire
En l'état, il semble que le .NET IObserver ne convient pas à plusieurs observateurs. Mais je suppose que votre objet principal (LocationReporter dans l'exemple) pourrait avoir
et cela vous permettrait de soutenir
ainsi que.
Je suppose que Microsoft pourrait faire valoir qu'il n'est donc pas nécessaire qu'ils prennent directement en charge plusieurs IObservables dans les interfaces.
la source
IObserver.OnComplete()
n'identifie pas de qui vient l'appel. Si l'observateur est abonné à plus d'un observable, il ne sait pas de qui se désabonner. Anticlimactique. Je me demande, .NET a-t-il une meilleure interface pour le modèle d'observateur?Observable.Create()
pour construire un observable, et en enchaînant plusieurs observables sources en utilisantSubscribe()
. J'ai par inadvertance passé un observable terminé dans un chemin de code. Ceci a complété mon observable nouvellement créé, même si les autres sources n'étaient pas complètes. Il m'a fallu des siècles à travailler sur ce que je devais faire - interrupteurObservable.Empty()
pourObservable.Never()
.Je sais que c'est bien tard pour la fête, mais ...
Les interfaces I
Observable<T>
et neIObserver<T>
font pas partie de Rx ... ce sont des types de base ... mais Rx en fait un usage intensif.Vous êtes libre d'avoir autant (ou aussi peu) d'observateurs que vous le souhaitez. Si vous prévoyez plusieurs observateurs, il est de la responsabilité de l'observable d'acheminer les
OnNext()
appels vers les observateurs appropriés pour chaque événement observé. L'observable peut avoir besoin d'une liste ou d'un dictionnaire comme vous le suggérez.Il y a de bons cas pour n'en autoriser qu'un - et de bons pour en autoriser plusieurs. Par exemple, dans une implémentation CQRS / ES, vous pouvez appliquer un seul gestionnaire de commandes par type de commande sur un bus de commandes, tandis que vous pouvez notifier plusieurs transformations côté lecture pour un type d' événement donné dans le magasin d'événements.
Comme indiqué dans d'autres réponses, il n'y a pas
Unsubscribe
. Jeter ce que l'on vous donne lorsque vous faitesSubscribe
généralement le sale boulot. L'observateur, ou un de ses agents, est responsable de conserver le jeton jusqu'à ce qu'il ne souhaite plus recevoir de notifications supplémentaires . (question 1)Donc, dans votre exemple:
... ce serait plutôt:
... où K entendrait 1003 et 1004 mais pas 1005.
Pour moi, cela semble toujours drôle parce que nominalement, les abonnements sont des choses qui durent longtemps ... souvent pour la durée du programme. Ils ne sont pas différents à cet égard des événements .Net normaux.
Dans de nombreux exemples que j'ai vus, le
Dispose
jeton fonctionne pour supprimer l'observateur de la liste d'observateurs de l'observable. Je préfère que le jeton ne transporte pas autant de connaissances ... et j'ai donc généralisé mes jetons d'abonnement pour simplement appeler un lambda transmis (avec des informations d'identification capturées au moment de l'abonnement:... et l'observable peut installer le comportement de désabonnement pendant l'abonnement:
Si votre observateur capture des événements de plusieurs observables, vous voudrez peut-être vous assurer qu'il existe une sorte d'informations de corrélation dans les événements eux-mêmes ... comme les événements .Net le font avec
sender
. C'est à vous de décider si cela compte ou non. Ce n'est pas intégré, comme vous l'avez raisonnablement raisonné. (question 3)la source