How do you establish whether or not a method should return IEnumerable
or IObservable
?
Why would I choose one paradigm over t
Use IEnumerable<T>
to represent lists, use IObservable<T>
to represent events. Easy peasy.
IEnumerable<T>
T
'sIObservable<T>
T
's is being "pushed" at youWhy would I choose one paradigm over the other?
You typically don't "choose" one paradigm over the other. Usually one stands out naturally as the correct choice, with the other one not making any sense.
Consider the following examples:
A huge CSV text file has an item on each line, and you want to process them one at a time without loading the entire file into memory at once: IEnumerable<List<string>>
You are running an HTTP web server: IObservable<WebRequest>
You want to do get the nodes of a tree data structure in a breadth-first manner: IEnumerable<Node>
You are responding to user interface button clicks: IObservable<Click>
In each of these examples (especially the IObservable<T>
cases), it just wouldn't make sense to use the other type.
IObservable<T>
to IEnumerable<T>
If something is naturally an IObservable<T>
but you want to process it as if it were an IEnumerable<T>
, you can do that with this method:
IEnumerable<T> Observable.ToEnumerable(this IObservable<T>)
T
gets "pushed" by the IObservable<T>
, it gets sent into a queue.T
out of the IEnumerable<T>
, it blocks until the queue isn't empty, then dequeues.IEnumerable<T>
to IObservable<T>
If something is naturally an IEnumerable<T>
but you want to process it as if it were an IObservable<T>
, you can do that with this method:
IObservable<T> Observable.ToObservable(this IEnumerable<T>)
T
from the IEnumerable<T>
.T
, it "pushes" it at you via the IObservable<T>
.IObservable<T> is a specialized interface that can be used for pub/sub and various other patterns. You would know when you needed to return an IObservable<T>
, so if there is not specific need then return IEnumerable<T>
.
Update to question in comment
Basically, IObservable<>
uses a "Push" mechanism and IEnumerable<> uses a "Pull" mechanism. If you are going to simply obtain a list of data that doesn't need to notify subscribers of changes (push) then you can use IEnumerable
. If a subscriber (Window, Control, other Client programs/routines, etc...) needs to know when data changed then use IObservable<>
. One example is using IObservable
to update the main UI thread in a windows program from a child thread (Normally this cannot be done without fancy footwork. Read up on .NET Reactive Extensions (Rx.NET).
Use IObservable<T>
if you want to push data to callers of your method at your convenience. You do this by calling OnNext()
on Observers
that registered interest via Subscribe()
.
Use IEnumerable<T>
if you want callers of your method to pull data at their convenience. They do this by calling GetEnumerator()
to acquire an IEnumerator
and calling MoveNext()
and Current
(foreach
compiles to this).
UPDATE: Perhaps best to give some examples:
A function that returns currency prices in a bank is a good candidate for IObservable<T>
. Here the information is time-critical. As the server of this data, you need to get it to the client as soon as possible. The client won't know when that data is ready. So you push it to them.
A function that returns the valid trading days for a particular financial instrument and is used to populate the blackout days on a calendar control is a good candidate for IEnumerable. This data rarely changes and the client (setting up the control) prefers to consume it at a pace it dictates.