Using Rx, I want to observe a legacy object that exposes both the method GetItems and the event NewItem.
When GetItems is called, it’ll synchronously return a list of any items it has in cache. It’ll also spawn an async fetch of items that will be published via the NewItem event as they are received.
How can I observe both of these sources (sync + async) in a consistent way by formulating a LINQ query such that both result-sets are captured? The production order is of no importance.
Let me see if I’ve understood your legacy object. I’m assuming it is a generic type that looks like this:
With the new item event args like this:
Now, I’ve created a
.ToObservable()extension method forLegacyObject<T>:This method creates a new observable for every subscriber – which is the correct thing to do when writing extension methods like this.
It creates a
gateobject to lock access to the internal list.Because you said that the act of calling
GetItemsspawns the async function to get new items I’ve made sure that theNewItemsubscription is created before the call toGetItems.The
innersubscription checks if the new item is in the list or not and only callsOnNexton the subject if it’s not in the list.The call to
GetItemsis made and the values are added to the internal list viaAddRange.There is an unlikely, but possible, chance that the items won’t be added to the list before the
NewItemevent begins firing on another thread. This is why there is a lock around the access to the list. Theinnersubscription will wait until it can obtain the lock before attempting to add items to the list and this will happen after the initial items are added to the list.Finally the internal list is turned into an observable, concatenated with the subject, and the
oobserver subscribes to this observable.The two subscriptions are returned as a single
IDisposableusingCompositeDisposable.And that is it for the
ToObservablemethod.Now, I tested this by creating a constructor on the legacy object that let me pass in both an enumerable and an observable of values. The enumerable is returned when the
GetItemsis called and the observable drives theNewItemevent.So, my test code looked like this:
And the values written to the console were:
Let me know if this meets your needs.