In .NET gibt es IObservable- und IObserver- Schnittstellen (auch hier und hier ). Interessanterweise enthält die konkrete Implementierung des IObservers keinen direkten Verweis auf das IObservable. Es weiß nicht, wen es abonniert hat. Es kann nur den Abmelder aufrufen. "Bitte ziehen Sie den Stift, um sich abzumelden."
edit: Der Abmelder implementiert das IDisposable
. Ich denke, dieses Schema wurde angewendet, um das Problem des erloschenen Hörers zu verhindern .
Zwei Dinge sind mir jedoch nicht ganz klar.
- Bietet die innere Unsubscriber-Klasse das Subscribe-and-Forget-Verhalten? Wer (und wann genau) ruft
IDisposable.Dispose()
den Abmelder an? Garbage Collector (GC) ist nicht deterministisch.
[Haftungsausschluss: Insgesamt habe ich mehr Zeit mit C und C ++ verbracht als mit C #.] Was soll passieren, wenn ich einen Beobachter K einem beobachtbaren L1 abonnieren möchte und der Beobachter bereits einen anderen beobachtbaren L2 abonniert hat?
K.Subscribe(L1); K.Subscribe(L2); K.Unsubscribe(); L1.PublishObservation(1003); L2.PublishObservation(1004);
Als ich diesen Testcode anhand des Beispiels von MSDN ausführte, blieb der Beobachter bei L1 abonniert. Dies wäre in der realen Entwicklung eigenartig. Möglicherweise gibt es drei Möglichkeiten, dies zu verbessern:
- Wenn der Beobachter bereits eine Instanz für das Abbestellen hat (dh sie ist bereits abonniert), wird er sich stillschweigend vom ursprünglichen Anbieter abmelden, bevor er eine neue abonniert. Dieser Ansatz verbirgt die Tatsache, dass er nicht mehr beim ursprünglichen Anbieter abonniert ist, was später zu einer Überraschung werden kann.
- Wenn der Beobachter bereits eine Abmeldeinstanz hat, wird eine Ausnahme ausgelöst. Ein gut erzogener Aufrufcode muss den Beobachter explizit abbestellen.
- Observer abonniert mehrere Anbieter. Dies ist die faszinierendste Option. Kann dies jedoch mit IObservable und IObserver implementiert werden? Mal schauen. Der Beobachter kann eine Liste der nicht abonnierten Objekte führen: eines für jede Quelle. Liefert leider
IObserver.OnComplete()
keinen Verweis auf den Anbieter, der ihn gesendet hat. Die IObserver-Implementierung mit mehreren Anbietern kann daher nicht bestimmen, von welchem Anbieter abgemeldet werden soll.
War der IObserver von .NET für das Abonnieren mehrerer IObservables vorgesehen?
Erfordert die Lehrbuchdefinition des Beobachtermusters, dass ein Beobachter mehrere Anbieter abonnieren kann? Oder ist es optional und implementierungsabhängig?
quelle
using
Block normalerweise nicht verwenden . Die Kosten für eine Abonnement-Anweisung sollten praktisch Null sein, also würden Sie den using-Block neter, abonnieren, den using-Block verlassen (also abbestellen), was den Code ziemlich sinnlos machtDu hast recht. Das Beispiel funktioniert schlecht für mehrere IObservables.
Ich denke, OnComplete () liefert keine Referenz zurück, weil sie nicht wollen, dass das IObservable es behalten muss. Wenn ich schreiben würde, dass ich wahrscheinlich mehrere Abonnements unterstützen würde, indem Subscribe einen Bezeichner als zweiten Parameter verwendet, der an den OnComplete () -Aufruf zurückgegeben wird. Man könnte also sagen
Derzeit scheint der .NET IObserver nicht für mehrere Beobachter geeignet zu sein. Aber ich nehme an, Ihr Hauptobjekt (LocationReporter im Beispiel) könnte haben
und das würde es Ihnen ermöglichen, zu unterstützen
auch.
Ich nehme an, Microsoft könnte argumentieren, dass sie daher nicht mehrere IObservables direkt in den Schnittstellen unterstützen müssen.
quelle
IObserver.OnComplete()
nicht identifiziert wird, von wem der Anruf kommt. Wenn der Beobachter mehr als ein Observable abonniert hat, weiß er nicht, von wem er sich abmelden soll. Enttäuschend. Ich frage mich, hat .NET eine bessere Schnittstelle für das Beobachtermuster?Observable.Create()
, um ein Observable zu erstellen, und mehrere Source-Observables mit verkettetSubscribe()
. Ich habe versehentlich ein abgeschlossenes Observable in einem Codepfad übergeben. Dies vervollständigte mein neu erstelltes Observable, obwohl die anderen Quellen nicht vollständig waren. Ich brauchte Ewigkeiten, um herauszufinden, was ich tun musste - wechselnObservable.Empty()
fürObservable.Never()
.Ich weiß, das ist viel zu spät zur Party, aber ...
Die Schnittstellen I
Observable<T>
undIObserver<T>
sind nicht Teil von Rx ... sie sind Kerntypen ... aber Rx nutzt sie ausgiebig.Es steht Ihnen frei, so viele (oder so wenige) Beobachter zu haben, wie Sie möchten. Wenn Sie mehrere Beobachter erwarten, liegt es in der Verantwortung des Beobachtbaren,
OnNext()
Anrufe für jedes beobachtete Ereignis an die entsprechenden Beobachter weiterzuleiten. Das Observable benötigt möglicherweise eine Liste oder ein Wörterbuch, wie Sie vorschlagen.Es gibt gute Fälle, in denen nur einer zugelassen wird - und gute Fälle, in denen viele zugelassen werden. In einer CQRS / ES-Implementierung können Sie beispielsweise einen einzelnen Befehlshandler pro Befehlstyp auf einem Befehlsbus erzwingen , während Sie möglicherweise mehrere leseseitige Transformationen für einen bestimmten Ereignistyp im Ereignisspeicher benachrichtigen .
Wie in anderen Antworten angegeben, gibt es keine
Unsubscribe
. Entsorgen Sie das, was Sie erhalten, wenn Sie imSubscribe
Allgemeinen die Drecksarbeit erledigen. Der Beobachter oder ein Vertreter davon ist dafür verantwortlich , an dem Token festzuhalten, bis er keine weiteren Benachrichtigungen mehr erhalten möchte . (Frage 1)Also, in Ihrem Beispiel:
... es wäre eher wie:
... wo K 1003 und 1004 hören würde, aber nicht 1005.
Für mich sieht das immer noch lustig aus, denn Abonnements sind nominell langlebige Dinge ... oft für die Dauer des Programms. Sie unterscheiden sich in dieser Hinsicht nicht von normalen .Net-Ereignissen.
In vielen Beispielen, die ich gesehen habe, entfernt der
Dispose
Token den Beobachter aus der Beobachterliste des Observablen. Ich bevorzuge, dass das Token nicht so viel Wissen enthält ... und deshalb habe ich meine Abonnement-Token so verallgemeinert, dass sie nur ein übergebenes Lambda aufrufen (mit identifizierenden Informationen, die zum Zeitpunkt des Abonnements erfasst wurden:... und das Observable kann das Abmeldeverhalten während des Abonnements installieren:
Wenn Ihr Beobachter Ereignisse von mehreren Observablen abfängt, möchten Sie möglicherweise sicherstellen, dass die Ereignisse selbst Korrelationsinformationen enthalten ... wie dies bei .Net-Ereignissen der Fall ist
sender
. Es liegt an Ihnen, ob das wichtig ist oder nicht. Es ist nicht eingebrannt, wie Sie richtig argumentiert haben. (Frage 3)quelle