Reactive Programming with the Rx Extensions
Note: This post is one of a series, the overview can be found here: Complex Event Processing with StreamInsight
In this chapter we are going to look at the StreamInsight 2.1 approach. We analyze and try to understand the interfaces that we met at the end of the last post.
We start by looking at where the different interfaces have their origin. This will give us clues on the functionality that they provide:
IEnumerable<T>: The IEnumerable interface comes from .NET 2.0 and has been there forever. We use it to describe an enumerable collection of items. All the common collections in .NET, such as Lists, Arrays, Sets, etc. implement the IEnumerable interface. It enriches the collection with functionality and is required if you want to “foreach” over a collection.
IQueryable<T>: IQueryable is the dual to IEnumerable. It serves the same purpose, describing a collection that contains enumerable items. The difference lies in the implementation. IQueryable can be used to access a remote collection of items. The interface contains an abstraction of the functionality of IEnumerable that can be projected onto any remote system, if there is a matching query provider available.
IObservable<T>: The IObservable interface can be found in the .NET 4.0 namespace. It fits together with the IObserver<T> interface and can be used to push data from the observable object to the observer object. We use it to implement publish-subscribe.
IQbservable<T>: Probably the interface with the strangest name ever, right? By the way, the Q stands for “Query”, as in IQueryable. IQbservable is to IObservable what IQueryable is to IEnumerable. This means that we can use IQbservable to implement the push paradigm with an observer that resides on a remote system.
IQStreamable<T>: IQStreamable is the interface that StreamInsight uses to represent a data stream.
Let’s look at the interfaces from a functional viewpoint:
On this image we can see how the interfaces are related in terms of PULL vs. PUSH and LOCAL vs. REMOTE.
Lets take a closer look at the difference in implementation of the PULL and the PUSH versions of the interfaces.
We can see that IEnumerable defines a GetEnumerator() method. The enumerator contains methods to navigate through the items in the collection.
On the other hand, the IQueryable interface is much more abstract. It provides an expression and a queryprovider. The expression is a statement represented in the form of an expression tree. An expression tree is an abstract construct that can represent a query such as the where clause in a LINQ statement.
The idea is that due to the abstract implementation of the expression, it can be sent to a remote system. On the remote system. The query provider is responsible for translating the expression into the language of the remote system. If we think about SqlServer, this might be SQL syntax.
We can see that the relation between IObservable and IQbservable has exactly the same purpose:
The IObservable interface provides an OnNext() method. Recall that we use it for publish-subscribe purposes. The OnNext() method is the place where the Observable pushes the data to the Observer. The IQbservable represents the logic in an expression and a query provider for remote execution.